jest możliwe, aby ChildWindow jak ChildWindow w Silverlight, ale dla WPF? Próbowałem dostosować Silverlight ChildWindow do WPF, ale napotkałem problemy z Transformations i nie mogłem ustawić Parent Popup. Próbuję stworzyć coś, co działa tak samo, więc nie muszę dodawać kodu do XAML dla wyskakujących okienek. Jakieś pomysły?Silverlight ChildWindow dla WPF
Odpowiedz
Klasa ta powinna robić to, co chcesz zrobić:
public class SilverlightishPopup
{
private Rectangle maskRectangle = new Rectangle { Fill = new SolidColorBrush(Colors.DarkGray), Opacity = 0.0 };
public FrameworkElement Parent
{
get;
set;
}
public FrameworkElement Content
{
get;
set;
}
public SilverlightishPopup()
{
Button button = new Button();
button.Width = 100;
button.Height = 200;
button.Content = "I am the popup!";
button.Click += delegate { Close(); };
Content = button;
}
public void Show()
{
Grid grid = GetRootGrid();
if (grid != null)
{
DoubleAnimation opacityAnimation = new DoubleAnimation(0.5, new Duration(TimeSpan.FromSeconds(0.5)));
Storyboard opacityBoard = new Storyboard();
opacityBoard.Children.Add(opacityAnimation);
Storyboard.SetTarget(opacityAnimation, maskRectangle);
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath("(Opacity)"));
opacityBoard.Completed += delegate
{
ScaleTransform scaleTransform = new ScaleTransform(0.0, 0.0, Content.Width/2.0, Content.Height/2.0);
Content.RenderTransform = scaleTransform;
grid.Children.Add(Content);
Storyboard scaleBoard = new Storyboard();
DoubleAnimation scaleXAnimation = new DoubleAnimation(1.0, TimeSpan.FromSeconds(0.5));
scaleBoard.Children.Add(scaleXAnimation);
Storyboard.SetTarget(scaleXAnimation, Content);
Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleX)"));
DoubleAnimation scaleYAnimation = new DoubleAnimation(1.0, TimeSpan.FromSeconds(0.5));
scaleBoard.Children.Add(scaleYAnimation);
Storyboard.SetTarget(scaleYAnimation, Content);
Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleY)"));
scaleBoard.Begin();
};
opacityBoard.Begin();
grid.Children.Add(maskRectangle);
}
}
public void Close()
{
Grid grid = GetRootGrid();
if (grid != null)
{
ScaleTransform scaleTransform = new ScaleTransform(1.0, 1.0, Content.Width/2.0, Content.Height/2.0);
Content.RenderTransform = scaleTransform;
Storyboard scaleBoard = new Storyboard();
DoubleAnimation scaleXAnimation = new DoubleAnimation(0.0, TimeSpan.FromSeconds(0.5));
scaleBoard.Children.Add(scaleXAnimation);
Storyboard.SetTarget(scaleXAnimation, Content);
Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleX)"));
DoubleAnimation scaleYAnimation = new DoubleAnimation(0.0, TimeSpan.FromSeconds(0.5));
scaleBoard.Children.Add(scaleYAnimation);
Storyboard.SetTarget(scaleYAnimation, Content);
Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleY)"));
scaleBoard.Completed += delegate
{
DoubleAnimation opacityAnimation = new DoubleAnimation(0.5, 0.0, new Duration(TimeSpan.FromSeconds(0.5)));
Storyboard opacityBoard = new Storyboard();
opacityBoard.Children.Add(opacityAnimation);
Storyboard.SetTarget(opacityAnimation, maskRectangle);
Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath("(Opacity)"));
opacityBoard.Completed += delegate
{
grid.Children.Remove(maskRectangle);
grid.Children.Remove(Content);
};
opacityBoard.Begin();
};
scaleBoard.Begin();
}
}
private Grid GetRootGrid()
{
FrameworkElement root = Parent;
while (root is FrameworkElement && root.Parent != null)
{
FrameworkElement rootElement = root as FrameworkElement;
if (rootElement.Parent is FrameworkElement)
{
root = rootElement.Parent as FrameworkElement;
}
}
ContentControl contentControl = root as ContentControl;
return contentControl.Content as Grid;
}
}
Wystarczy ustawić właściwość dominującą do dowolnego elementu ramowego w oknie macierzystej (będzie ona znaleźć okno do blokowania go z maską), oraz ustaw zawartość na wszystko, co chcesz, aby pojawił się na ekranie (i wywołaj metodę Show, jeśli chcesz, aby była wyświetlana, oczywiście). Będziesz musiał wymyślić okienko pop-up (np. Coś z ramką i przyciskiem zamykającym, który wywoła metodę close) na własną rękę, ale nie powinno to być trudne i oczywiście usunąć przycisk zastępczy w konstruktorze (jest tam tylko po to, aby pokazać, jak to będzie wyglądać).
Jedynym problemem jest to, że działa on tylko w oknach, które mają swoją zawartość (tj. Rzecz o nazwie "LayoutRoot" w Silverlight) jest siatką (domyślną, gdy tworzysz nowe okno/stronę WPF/Silverlight). Miałem to ustawione do pracy dla wszystkich paneli, ale wygląda dziwnie, gdy jest używane z StackPanel lub DockPanel (zgodnie z oczekiwaniami). Jeśli to ci nie pomoże, daj mi znać, a my coś wymyślimy.
Jeśli grasz z tym, prawdopodobnie możesz uzyskać animację, aby przyjrzeć się bliżej oryginalnemu wyskakującemu okienko (być może za pomocą nieco luzu). Może być lepszy sposób na odnalezienie root'a, po prostu wymyśliłem tę metodę w locie, ale myślę, że zadziała (choć znowu tylko z ContentControl z zawartością ustawioną na siatkę).
Daj mi znać, jeśli masz jakieś pytania/problemy i mam nadzieję, że to rozwiąże Twój problem.
Wystarczy wywnioskować z okna i wywołać ShowDialog z okna nadrzędnego.
to wszystko cacy, ale nie chcę się nowe okno. Chcę móc pokazać zasłonę w bieżącym oknie i mieć nowe okno ChildWindow pokazane wewnątrz bieżącego. Jestem całkowicie famair z tym, jak działa okno i jak tworzyć okna i okna dialogowe, ale to nie jest mój cel tutaj. Moim celem jest, jak powiedziałem w powyższym poście, takie samo odczucie jak ChildWindow silverlighta, ale w WPF. – Jeff
Co dziwne, to było to, czego szukałem, ale nie zostało ono przegłosowane, więc nie przeczytałem tego. W końcu zdałem sobie sprawę, że klasa okna WPF jest tym, czego potrzebowałem do modalnego dialogu w WPF. To prawda, że nie jest to dokładnie jak ChildWindow Silverlight. Ale jest modalny, o ile nazwiesz ShowDialog. Cały mój kod Silverlight, który używa portów ChildWindow z łatwością, jeśli tylko zmienię konstruktor na Window i Show to ShowDialog. –
Wydaje mi się, że program ShowOverog z WPF blokuje bieżący wątek, podczas gdy ShowDialog z WPF go blokuje, więc musisz uważać, aby logika kodu nie zepsuła się. –
Spójrz na BubbleBurst Sourcecode. GameOverView robi dokładnie to, czego szukasz.
Patrz ów kontroli ChildWindow dostępne w rozszerzonym WPF Toolkit tutaj http://wpftoolkit.codeplex.com/wikipage?title=ChildWindow&referringTitle=Home
Zmienili tam klasy ChildWindows i MessageBox - "Począwszy od wersji 2.0, MessageBox (i ChildWindow) pochodzi z WindowControl i nie zarządza już tłem swojego rodzica ani jego pozycjonowaniem w oparciu o rozmiar jego rodzica. WindowContainer powinien teraz być użyte do powstrzymania tych kontroli." –
btw, mówią, że starsza wersja pozostanie dostępna, ale nie wiesz, gdzie znajduje się najnowsza wersja repozytorium –
Nie możesz wstrzykiwać rodzicowi Grid przed rootem dynamicznie i usunąć kiedy skończysz? –
wow no xaml przykład ??? – user1034912