2010-06-02 7 views
10

Me gustaría construir un diálogo modal genérico/reutilizable que pueda usar en nuestra aplicación WPF (MVVM) - WCF LOB.Cómo crear un cuadro de diálogo modal genérico/reutilizable para WPF después de MVVM

Tengo una vista y un ViewModels asociado que me gustaría mostrar usando diálogos. Los enlaces entre Vistas y Modelos de Vista se hacen usando Plantillas de Datos dirigidas por Tipo.

Éstos son algunos de los requisitos que he podido redactar: ​​

  • prefiero que esto se basa en una ventana en vez de usar Adorners y controles que actúan como un cuadro de diálogo modal.
  • Debe obtener su tamaño mínimo del contenido.
  • Debe centrarse en la ventana del propietario.
  • La ventana no debe mostrar los botones Minimizar y Maximizar.
  • Debería obtener su título del contenido.

¿Cuál es la mejor manera de hacerlo?

Respuesta

7

Estoy respondiendo mi propia pregunta para ayudar a otros a encontrar todas las respuestas que me costó encontrar en un solo lugar. Lo que arriba parece un problema directo, en realidad presenta múltiples problemas que espero responder lo suficientemente a continuación.

Aquí va.

Su ventana de WPF que servirá como el cuadro de diálogo genérico puede ser algo como esto:

<Window x:Class="Example.ModalDialogView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:ex="clr-namespace:Example" 
     Title="{Binding Path=mDialogWindowTitle}" 
     ShowInTaskbar="False" 
     WindowStartupLocation="CenterOwner" 
     WindowStyle="SingleBorderWindow" 
     SizeToContent="WidthAndHeight" 
     ex:WindowCustomizer.CanMaximize="False" 
     ex:WindowCustomizer.CanMinimize="False" 
     > 
    <DockPanel Margin="3"> 
     <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" FlowDirection="RightToLeft"> 
      <Button Content="Cancel" IsCancel="True" Margin="3"/> 
      <Button Content="OK" IsDefault="True" Margin="3" Click="Button_Click" /> 
     </StackPanel> 
     <ContentPresenter Name="WindowContent" Content="{Binding}"/> 
    </DockPanel> 
</Window> 

Siguiendo MVVM, de la manera correcta para mostrar un cuadro de diálogo es a través de un mediador. Para usar un mediador, normalmente también necesita un localizador de servicios. Para detalles específicos del mediador, mira here.

La solución que establecí implicó la implementación de una interfaz IDialogService que se resuelve a través de un simple ServiceLocator estático. This excelente artículo del proyecto de código tiene los detalles sobre eso. Tome nota del mensaje this en el foro del artículo. Esta solución también resuelve el problema de descubrir la ventana del propietario a través de la instancia de ViewModel.

Usando esta interfaz, puede llamar a IDialogService.ShowDialog (ownerViewModel, dialogViewModel). Por ahora, estoy llamando esto desde el propietario ViewModel, lo que significa que tengo referencias difíciles entre mis ViewModels.Si usa eventos agregados, probablemente lo llamará un conductor.

Al establecer el tamaño mínimo en la Vista que se mostrará finalmente en el cuadro de diálogo, no se establece automáticamente el tamaño mínimo del cuadro de diálogo. Además, dado que el árbol lógico en el cuadro de diálogo contiene ViewModel, no puede vincularse solo a las propiedades del elemento WindowContent. This pregunta tiene una respuesta con mi solución.

La respuesta que menciono arriba también incluye un código que centra la ventana en el propietario.

Por último, deshabilitar los botones minimizar y maximizar es algo que WPF no puede hacer de forma nativa. La solución más elegante en mi humilde opinión es usar this.

11

lo general lidiar con esto mediante la inyección de esta interfaz en los ViewModels apropiadas:

public interface IWindow 
{ 
    void Close(); 

    IWindow CreateChild(object viewModel); 

    void Show(); 

    bool? ShowDialog(); 
} 

Esto permite que el ViewModels a Spaw ventanas hijas y los muestran de forma modal en modal.

Una aplicación reutilizable de IWindow es la siguiente:

public class WindowAdapter : IWindow 
{ 
    private readonly Window wpfWindow; 

    public WindowAdapter(Window wpfWindow) 
    { 
     if (wpfWindow == null) 
     { 
      throw new ArgumentNullException("window"); 
     } 

     this.wpfWindow = wpfWindow; 
    } 

    #region IWindow Members 

    public virtual void Close() 
    { 
     this.wpfWindow.Close(); 
    } 

    public virtual IWindow CreateChild(object viewModel) 
    { 
     var cw = new ContentWindow(); 
     cw.Owner = this.wpfWindow; 
     cw.DataContext = viewModel; 
     WindowAdapter.ConfigureBehavior(cw); 

     return new WindowAdapter(cw); 
    } 

    public virtual void Show() 
    { 
     this.wpfWindow.Show(); 
    } 

    public virtual bool? ShowDialog() 
    { 
     return this.wpfWindow.ShowDialog(); 
    } 

    #endregion 

    protected Window WpfWindow 
    { 
     get { return this.wpfWindow; } 
    } 

    private static void ConfigureBehavior(ContentWindow cw) 
    { 
     cw.WindowStartupLocation = WindowStartupLocation.CenterOwner; 
     cw.CommandBindings.Add(new CommandBinding(PresentationCommands.Accept, (sender, e) => cw.DialogResult = true)); 
    } 
} 

Se puede utilizar esta ventana como una ventana de acogida reutilizable. No hay código subyacente:

<Window x:Class="Ploeh.Samples.ProductManagement.WpfClient.ContentWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:self="clr-namespace:Ploeh.Samples.ProductManagement.WpfClient" 
     xmlns:pm="clr-namespace:Ploeh.Samples.ProductManagement.PresentationLogic.Wpf;assembly=Ploeh.Samples.ProductManagement.PresentationLogic.Wpf" 
     Title="{Binding Path=Title}" 
     Height="300" 
     Width="300" 
     MinHeight="300" 
     MinWidth="300" > 
    <Window.Resources> 
     <DataTemplate DataType="{x:Type pm:ProductEditorViewModel}"> 
      <self:ProductEditorControl /> 
     </DataTemplate> 
    </Window.Resources> 
    <ContentControl Content="{Binding}" /> 
</Window> 

Puede leer más sobre esto (así como descargar el ejemplo de código completo) en my book.

+0

Gracias por mostrar su enfoque! –

+0

¿Por qué el voto anónimo? –

Cuestiones relacionadas