2010-02-08 13 views
11

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

9

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.

+0

Nie możesz wstrzykiwać rodzicowi Grid przed rootem dynamicznie i usunąć kiedy skończysz? –

+0

wow no xaml przykład ??? – user1034912

1

Wystarczy wywnioskować z okna i wywołać ShowDialog z okna nadrzędnego.

+0

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

+0

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. –

+0

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ę. –

2

Patrz ów kontroli ChildWindow dostępne w rozszerzonym WPF Toolkit tutaj http://wpftoolkit.codeplex.com/wikipage?title=ChildWindow&referringTitle=Home

+0

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." –

+0

btw, mówią, że starsza wersja pozostanie dostępna, ale nie wiesz, gdzie znajduje się najnowsza wersja repozytorium –

Powiązane problemy