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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:34:41  来源:igfitidea点击:

Open a new Window in MVVM

c#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 LightPrism
在此MainWindow我想单击 aMenuItemButton打开一个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 :

ResourceDitionaryMainWindow我有:

<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到 aMenuItemButton
我知道这不是正确的方法,但是这样做的正确方法是什么?

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 的构造函数中实现了,并且新窗口的创建委托给该对象。这允许您在测试期间将生产实现替换为不同的实现。