假设我有一个MainWindow
和一个MainViewModel
,我在这个例子中没有使用 MVVM Light 或 Prism 。
在此MainWindow
我想点击MenuItem
或Button
以打开NewWindow.xaml
而不是UserControl
。
我知道如何使用UserControl
在UserControl
或ContrntControl
的现有窗口中打开新的Frame
。
<ContentControl Content="{Binding Path=DisplayUserControl,UpdateSourceTrigger=PropertyChanged}" />
代码
public ViewModelBase DisplayUserControl
{
get
{
if (displayUserControl == null)
{
displayUserControl = new ViewModels.UC1iewModel();
}
return displayUserControl;
}
set
{
if (displayUserControl == value)
{
return;
}
else
{
displayUserControl = value;
OnPropertyChanged("DisplayUserControl");
}
}
}
ResourceDitionary
MainWindow
我有:
<DataTemplate DataType="{x:Type localViewModels:UC1ViewModel}">
<localViews:UC1 />
</DataTemplate>
<DataTemplate DataType="{x:Type localViewModels:UC2ViewModel}">
<localViews:UC2 />
</DataTemplate>
问题是我要打开一个新的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
。
我知道这不是正确的方法,但是这样做的正确方法是什么?
谢谢!
答案 0 :(得分:21)
使用此类应用程序需要解决两个问题。
首先,您不希望View-Model直接创建和显示UI组件。使用MVVM的一个动机是将测试能力引入到View-Model中,并且让这个类弹出新窗口使得这个类更难以测试。
您需要解决的第二个问题是如何解决应用程序中的依赖关系,或者在此实例中 - 如何将View-Model“挂钩”到相应的View?通过使用DI容器给出了后一问题的可维持解决方案。 Mark Seemann的Dependency Injection in .NET给出了这个主题的一个很好的参考。他实际上也讨论了如何解决第一个问题!
要解决前一个问题,需要在代码中引入一层间接,以使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
,并且此对象将委派新窗口的创建。这允许您在测试期间将生产实现替换为不同的实现。