2010-02-08 11 views
11

¿es posible hacer una ChildWindow como ChildWindow en Silverlight, pero para WPF? Traté de adaptar Silverlight ChildWindow a WPF pero tuve problemas con Transformations y no pude configurar Popup's Parent. Estoy tratando de hacer algo que funcione de manera simular, así no tengo que agregar código al XAML para las ventanas emergentes. ¿Algunas ideas?Silverlight ChildWindow para WPF

Respuesta

9

Esta clase debe hacer lo que quiere hacer:

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; 
    } 
} 

acaba de establecer la propiedad Parent a cualquier elemento de marco en la ventana padre (que va a encontrar la ventana de bloquearlo con la máscara), y establece el contenido a lo que quieras que aparezca (y llama al método Show cuando quieras que se muestre, por supuesto). Tendrás que crear el contenedor emergente (es decir, algo con un borde y un botón de cerrar que llama al método de cierre) por tu cuenta, pero no debería ser difícil, y obviamente eliminar el botón de marcador de posición en el constructor (está ahí para mostrarle cómo se verá).

El único problema con esto es que solo funcionará en las ventanas que tienen su contenido (es decir, lo que se llama "LayoutRoot" en Silverlight) es una cuadrícula (la predeterminada al crear una nueva ventana/página de WPF/Silverlight) Lo tenía listo para todos los paneles, pero se ve raro cuando se usa con un StackPanel o un DockPanel (como se esperaba). Si eso no funciona para usted, hágamelo saber y resolveremos algo.

Si juegas con él, probablemente puedas hacer que la animación se parezca más a la ventana emergente original (quizás usando un poco de relajación). También podría haber una forma mejor de encontrar la raíz. Acabo de idear ese método sobre la marcha, pero creo que funcionará (aunque, nuevamente, solo con Contentcontrol con su contenido configurado en una cuadrícula).

Avíseme si tiene alguna pregunta o problema, y ​​espero que esto resuelva su problema.

+0

no puede inyectar un padre Grid ante la raíz de forma dinámica y eliminar cuando se hace? –

+0

wow no xaml example ??? – user1034912

1

Simplemente derive de la ventana y llame a ShowDialog desde la ventana principal.

+0

Eso es todo lo fino y elegante, pero no quiero una nueva ventana. Quiero poder mostrar un velo sobre la ventana actual, y tener el nuevo ChildWindow mostrado dentro del actual. Estoy completamente familiarizado con cómo funciona Windows y cómo hacer ventanas y diálogos, pero ese no es mi objetivo aquí. Mi objetivo es como dije en la publicación anterior, la misma sensación que SilverWindow, pero en WPF. – Jeff

+0

Curiosamente, esto era lo que estaba buscando, pero todavía no se había votado, así que no lo leí. Finalmente me di cuenta de que la clase Window de WPF es lo que necesitaba para un diálogo modal en WPF. Es cierto que no es exactamente como ChildWindow de Silverlight. Pero es modal, siempre que llame a ShowDialog. Todo mi código Silverlight que usa puertos ChildWindow con facilidad, si solo cambio el constructor a Window y Show to ShowDialog. –

+0

Creo que Show of Silverlight's ChildWindow no bloquea el hilo actual, mientras que ShowDialog de WPF lo bloquea, por lo que debe tener cuidado de que la lógica del código no se rompa –

2

Ver la eso de control de ChildWindow disponible en el kit de herramientas de WPF extendido aquí http://wpftoolkit.codeplex.com/wikipage?title=ChildWindow&referringTitle=Home

+0

han cambiado las clases ChildWindows y MessageBox allí: "Comenzando con la versión 2.0, MessageBox (y ChildWindow) se deriva de WindowControl y ya no administra el fondo de su padre o el posicionamiento de sí mismo en función del tamaño de su padre. ser utilizado para contener estos controles." –

+0

por cierto, dicen que la versión anterior seguirá estando disponible, pero no está seguro de dónde está en la última versión del repositorio –

Cuestiones relacionadas