在MVVM中打开一个新窗口
假设我有一个MainWindow
和一个MainViewModel
,我在这个例子中没有使用MVVM Light或Prism 。
在这个MainWindow
我想单击一个MenuItem
或Button
来打开一个NewWindow.xaml
而不是一个UserControl
。
我知道如何使用UserControl
在ContrntControl
或Frame
现有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"); } } }
在MainWindow
的ResourceDitionary
,我有:
问题是我想打开一个新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
绑定到MenuItem
或Button
。
我知道这不是正确的方法,但是这样做的正确方法是什么?
谢谢!
使用此类应用程序需要解决两个问题。
首先,您不希望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
,并且此对象将委托创建新窗口。 这允许您在测试期间将生产实现替换为不同的实现。