C# 在 MVVM 中打开一个新窗口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16652501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Open a new Window in MVVM
提问by xargs
Lets say I have a MainWindowand a MainViewModel, I'm not using MVVM Lightor Prismin this example.
In this MainWindowI want to click a MenuItemor Buttonto open a NewWindow.xamlnot a UserControl.
I know how to use this with UserControlto open a new UserControlin my existing Window in a ContrntControlor a Frame.
假设我有 aMainWindow和 a MainViewModel,在这个例子中我没有使用MVVM Light或Prism。
在此MainWindow我想单击 aMenuItem或Button打开一个NewWindow.xamlnot a UserControl。
我知道如何使用它在 a或 a 中的现有窗口中UserControl打开一个新UserControl窗口。ContrntControlFrame
<ContentControl Content="{Binding Path=DisplayUserControl,UpdateSourceTrigger=PropertyChanged}" />
Code
代码
public ViewModelBase DisplayUserControl
{
get
{
if (displayUserControl == null)
{
displayUserControl = new ViewModels.UC1iewModel();
}
return displayUserControl;
}
set
{
if (displayUserControl == value)
{
return;
}
else
{
displayUserControl = value;
OnPropertyChanged("DisplayUserControl");
}
}
}
In the ResourceDitionaryfor MainWindowI have :
在ResourceDitionary对MainWindow我有:
<DataTemplate DataType="{x:Type localViewModels:UC1ViewModel}">
<localViews:UC1 />
</DataTemplate>
<DataTemplate DataType="{x:Type localViewModels:UC2ViewModel}">
<localViews:UC2 />
</DataTemplate>
The thing is that I want to open a new Window, not a UserControl. So I use some code like this :
问题是我想打开一个新的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();
}
and then a bind OpenNewWindowto a MenuItemor Button.
I know this is not the right way, but what is the right way to do this ?
然后绑定OpenNewWindow到 aMenuItem或Button。
我知道这不是正确的方法,但是这样做的正确方法是什么?
Thanks!
谢谢!
采纳答案by Lawrence
There are two problems you need to solve with this type of application.
对于此类应用程序,您需要解决两个问题。
Firstly, you do not want to have the View-Model creating and displaying UI components directly. One of the motivations for using MVVM is to introduce test-ability in to your View-Model, and having this class pop up new windows makes this class harder to test.
首先,您不想让 View-Model 直接创建和显示 UI 组件。使用 MVVM 的动机之一是将可测试性引入到您的视图模型中,并且让此类弹出新窗口会使此类更难测试。
The second problem you need to solve is how to resolve the dependencies in your application, or in this instance – how to you “hook up” the View-Model to the corresponding View? A maintainable solution to this latter problem is given by the use of a DI container. A very good reference to this subject is given by Mark Seemann's Dependency Injection in .NET. He actually also discusses how to solve the first problem too!
您需要解决的第二个问题是如何解决您的应用程序中的依赖关系,或者在这种情况下——如何将 View-Model 与相应的 View “挂钩”?后一个问题的可维护解决方案是通过使用 DI 容器给出的。Mark Seemann's Dependency Injection in .NET对这个主题给出了很好的参考。他居然也讨论了如何解决第一个问题!
To solve the former problem, you need to introduce a layer of indirection to your code, to make the View-Model not dependent on a concrete implementation of creating a new window. A very simple example is given in the code below:
为了解决前一个问题,你需要在你的代码中引入一个间接层,使 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
}
Note that you take an implementation of IWindowFactoryin the constructor of your View-Model, and it is to this object that the creation of the new window is delegated to. This allows you to substitute the production implementation for a different one during testing.
请注意,您IWindowFactory在 View-Model 的构造函数中实现了,并且新窗口的创建委托给该对象。这允许您在测试期间将生产实现替换为不同的实现。

