WPF从ViewModel打开一个新视图

Gui*_*ira 7 c# wpf xaml mvvm

这是我的第一个WPF-MVVM应用程序,这是我的结构:

  1. app.xaml用一个项目打开应用程序并覆盖OnStartup以解决MainWindow.(由于参考,我这样做了);
  2. 我的观点的一个项目;
  3. 我的ViewModels的一个项目;
  4. 我的模型的一个项目.

我有以下问题:我在上面,MainWindowView然后点击按钮显示另一个视图.我应该怎么做,从我打开这个另一种观点MainWindowViewModel,而我View Project与具有一定的参考ViewModel Project,我不能引用ViewModel ProjectView Project

顺便说一句,我使用Unitydependency injection.

那么,你能帮帮我吗?

Art*_*nes 10

有几种方法可以解决这个问题.

您可以定义在ViewModels项目中定义的对话框/导航/窗口服务接口.您需要决定ViewModel如何表达他们想要打开的窗口.我一般用的IDialogViewModel接口,其中一些我的ViewModels的实施,并通过视图模型的实例来服务,但您可以使用一个枚举,字符串,任何你想要的,这样您的实施可以映射到真正的窗口,这将是打开.

例如:

public interface IDialogService
{
    bool? ShowDialog(object dialogViewModel); 
}
Run Code Online (Sandbox Code Playgroud)

想要打开新Windows的ViewModel将接收该服务的实例,并使用它来表示打开Window的意图.在Views项目中,您将定义一个实现服务接口的类型,并打开Window后面的真实逻辑.

以下示例:

public class DialogService : IDialogService
{
    private Stack<Window> windowStack = new Stack<Window>();


    public DialogService(Window root)
    {
        this.windowStack.Push(root);
    }

    public bool? ShowDialog(object dialogViewModel)
    {
        Window dialog = MapWindow(dialogViewModel); 
        dialog.DataContext = dialogViewModel;
        dialog.Owner = this.windowStack.Peek();

        this.windowStack.Push(dialog);

        bool? result;

        try
        {
            result = dialog.ShowDialog();
        }
        finally
        {
            this.windowStack.Pop();
        }

        return result;
    }

}
Run Code Online (Sandbox Code Playgroud)

您的主项目将负责在需要它的ViewModel中创建和注入对话框服务.在该示例中,App将创建一个将MainWindow传递给它的新对话服务实例.

类似的方法是使用某种形式的消息传递模式(link1 link2).此外,如果你想要简单的东西,你也可以让你的ViewModel在他们想要打开Windows并让Views订阅它们时引发事件.

编辑

我在我的应用程序中使用的完整解决方案通常有点复杂,但基本上就是这个想法.我有一个基本的DialogWindow,它需要一个实现IDialogViewModel接口的ViewModel作为DataContext.此接口抽象出您在对话框中期望的一些功能,例如接受/取消命令以及关闭事件,因此您也可以从ViewModel关闭窗口.DialogWindow基本上包含一个ContentPresenter,它将Content属性绑定到DataContext,并在DataContext被更改时挂钩close事件(以及其他一些事情).

每个"对话框"包含一个IDialogViewModel和一个关联的View(UserControl).为了映射它们,我只是在App的资源中声明隐式DataTemplates.在我所展示的代码中,唯一的区别是没有方法MapWindow,窗口实例将始终是DialogWindow.

我使用额外的技巧在对话框之间重用布局元素.方法是将它们包含在DialogWindow中(接受/取消按钮等).我喜欢保持DialogWindow干净(所以我可以将它用于"非对话框"对话框).我宣布一个模板与常见的界面元素ContentControl中,当我宣布一个视图查看模型映射模板,我换用我的应用"对话框模板"一ContentControl中查看.然后,您可以根据需要为DialogWindow提供尽可能多的"主模板"(例如,像"向导之类").