2010-06-02 25 views
10

我想构建一个通用/可重用的模式对话框,可以在我们的WPF(MVVM)中使用 - WCF LOB应用程序。如何为MVVM构建一个通用/可重用的模态对话框MVVM

我有一个Views和相关的ViewModels,我想使用对话框显示。视图和ViewModel之间的绑定是使用Type-targeted DataTemplates完成的。

这里有一些要求,我已经能够起草:

  • 我宁愿这是基于一个窗口,而不是使用像一个模态对话框装饰器和控制。
  • 它应该从内容中获得其最小尺寸。
  • 它应该以所有者窗口为中心。
  • 该窗口不能显示最小化和最大化按钮。
  • 它应该从内容中获得它的标题。

这样做的最好方法是什么?

回答

7

我回答我自己的问题,以帮助别人找到我在一个地方找到的所有答案。上面的问题似乎是一个直截了当的问题,实际上提出了许多问题,我希望能够在下面做出充分回答

在这里。

您的WPF窗口,将作为通用对话框可以是这个样子:

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

继MVVM,显示一个对话框,正确的方法是通过中介。要使用中介,您通常还需要一些服务定位器。有关调解员的具体细节,请查看here

我解决的解决方案涉及实现通过简单静态ServiceLocator解析的IDialogService接口。 This优秀的codeproject文章有详细的说明。在文章论坛中注意this消息。该解决方案还解决了通过ViewModel实例发现所有者窗口的问题。

使用此接口,可以调用IDialogService.ShowDialog(ownerViewModel,dialogViewModel)。现在,我从所有者ViewModel调用它,这意味着我在ViewModel之间有很多参考。如果你使用聚合事件,你可能会从指挥中调用。

在最终显示在对话框中的视图上设置最小尺寸不会自动设置对话框的最小尺寸。另外,由于对话框中的逻辑树包含ViewModel,因此不能只绑定到WindowContent元素的属性。 This问题有我的解决方案的答案。

上面我提到的答案还包括以窗口为中心的代码。

最后,禁用最小化和最大化按钮是WPF本来无法做到的。最优雅的解决方案恕我直言,使用this

11

我通常通过注射该接口到适当的ViewModels这个处理:

public interface IWindow 
{ 
    void Close(); 

    IWindow CreateChild(object viewModel); 

    void Show(); 

    bool? ShowDialog(); 
} 

这允许的ViewModels到SPAW子窗口和模态并将它们显示在无模式。

可重用实现IWindow的是这样的:

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

您可以使用此窗口,可重复使用的主窗口。有没有后台代码:

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

你可以阅读更多关于这个(以及下载完整的代码示例)在my book

+0

感谢您展示您的方法! – 2010-06-02 11:02:04

+0

为什么匿名downvote? – 2011-04-13 08:28:51