在MVVM中打开一个新窗口

时间:2013-05-20 15:06:23

标签: c# mvvm

假设我有一个MainWindow和一个MainViewModel,我在这个例子中没有使用 MVVM Light Prism
在此MainWindow我想点击MenuItemButton以打开NewWindow.xaml而不是UserControl
我知道如何使用UserControlUserControlContrntControl的现有窗口中打开新的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();
}

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

谢谢!

1 个答案:

答案 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,并且此对象将委派新窗口的创建。这允许您在测试期间将生产实现替换为不同的实现。