在MVVM中打开一个新窗口

xar*_*rgs 10 c# mvvm

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

<ContentControl Content="{Binding Path=DisplayUserControl,UpdateSourceTrigger=PropertyChanged}" />
Run Code Online (Sandbox Code Playgroud)

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

ResourceDitionaryMainWindow我有:

<DataTemplate DataType="{x:Type localViewModels:UC1ViewModel}">
    <localViews:UC1 />
</DataTemplate>
<DataTemplate DataType="{x:Type localViewModels:UC2ViewModel}">
    <localViews:UC2 />
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

问题是我想开一个新的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();
}
Run Code Online (Sandbox Code Playgroud)

然后绑定OpenNewWindowMenuItemButton.
我知道这不是正确的方法,但是这样做的正确方法是什么?

谢谢!

Law*_*nce 23

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

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

您需要解决的第二个问题是如何解决应用程序中的依赖关系,或者在这个实例中 - 如何将View-Model"挂钩"到相应的View?通过使用DI容器给出了后一问题的可维持解决方案.Mark Seemann 在.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
}
Run Code Online (Sandbox Code Playgroud)

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