在MVVM中打开一个新窗口

假设我有一个MainWindow和一个MainViewModel ,我在这个例子中没有使用MVVM LightPrism
在这个MainWindow我想单击一个MenuItemButton来打开一个NewWindow.xaml而不是一个UserControl
我知道如何使用UserControlContrntControlFrame现有Window中打开一个新的UserControl

  

 public ViewModelBase DisplayUserControl { get { if (displayUserControl == null) { displayUserControl = new ViewModels.UC1iewModel(); } return displayUserControl; } set { if (displayUserControl == value) { return; } else { displayUserControl = value; OnPropertyChanged("DisplayUserControl"); } } } 

MainWindowResourceDitionary ,我有:

       

问题是我想打开一个新Window ,而不是UserControl 。 所以我使用这样的代码:

 private ICommand openNewWindow; public ICommand OpenNewWindow { get { return openNewWindow; } } public void DoOpenNewWindow() { View.NewWindowWindow validationWindow = new View.NewWindow(); NewWindowViewModel newWindowViewModel = new NewWindowViewModel(); newWindow.DataContext = ewWindowViewModel; newWindow.Show(); } 

然后将OpenNewWindow绑定到MenuItemButton
我知道这不是正确的方法,但是这样做的正确方法是什么?

谢谢!

使用此类应用程序需要解决两个问题。

首先,您不希望View-Model直接创建和显示UI组件。 使用MVVM的一个动机是将测试能力引入到View-Model中,并且让这个类弹出新窗口使得这个类更难以测试。

您需要解决的第二个问题是如何解决应用程序中的依赖关系,或者在这个实例中 – 如何将View-Model“挂钩”到相应的View? 通过使用DI容器给出了后一问题的可维持解决方案。 Mark Seemann 在.NET中的dependency injection给出了这个主题的一个很好的参考。 他实际上也讨论了如何解决第一个问题!

要解决前一个问题,需要在代码中引入一个间接层,以使View-Model不依赖于创建新窗口的具体实现。 下面的代码给出了一个非常简单的示例:

 public class ViewModel { private readonly IWindowFactory m_windowFactory; private ICommand m_openNewWindow; public ViewModel(IWindowFactory windowFactory) { m_windowFactory = windowFactory; /** * Would need to assign value to m_openNewWindow here, and associate the DoOpenWindow method * to the execution of the command. * */ m_openNewWindow = null; } public void DoOpenNewWindow() { m_windowFactory.CreateNewWindow(); } public ICommand OpenNewWindow { get { return m_openNewWindow; } } } public interface IWindowFactory { void CreateNewWindow(); } public class ProductionWindowFactory: IWindowFactory { #region Implementation of INewWindowFactory public void CreateNewWindow() { NewWindow window = new NewWindow { DataContext = new NewWindowViewModel() }; window.Show(); } #endregion } 

请注意,您在View-Model的构造函数中执行了IWindowFactory ,并且此对象将委托创建新窗口。 这允许您在测试期间将生产实现替换为不同的实现。