2010-06-02 38 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