在WPF中使用MVVM,我应该从后面的View代码或ViewModel启动子窗口吗?

问题描述 投票:17回答:6

我有一段时间对此感到困惑。我正在使用MVVM模式编写相当大的RibbonWindow WPF应用程序。屏幕顶部有一个RibbonBar菜单,其余部分显示各种视图。某些视图包含其他视图,其中一些视图具有启动子窗口的按钮。

到目前为止,我一直在使用View代码隐藏文件执行此操作,但我知道在使用MVVM时这些文件应该是空的。我可以将子窗口启动代码移动到ViewModel,但是我需要引用主RibbonWindow(设置为子窗口所有者),这似乎不正确。

关于如何使用MVVM正常实现这一建议或提示将不胜感激。

wpf mvvm view viewmodel childwindow
6个回答
19
投票

我通常通过创建某种WindowViewLoaderService来处理这个问题。当您的程序初始化时,您使用以下代码注册Window和ViewModel:

WindowViewLoaderService.Register(TypeOf(MainWindowView), TypeOf(MainWindowViewModel));
WindowViewLoaderService.Register(TypeOf(MyWindowView), TypeOf(MyWindowViewModel));

然后,当您可以从ViewModel调用此服务时,您需要引用的只是另一个ViewModel。例如,如果您在MainWindowViewModel中,则可能具有以下代码:

var myChildWindowVM = new MyWindowViewModel();
WindowViewLoaderService.ShowWindow(myChildWindowVM);

然后,WindowViewLoaderService将查找与您传递的指定ViewModel关联的View。它将创建View,将其DataContext设置为您传入的ViewModel,然后显示View。

这样您的ViewModels就不会知道任何视图。

您可以非常轻松地推出自己的其中一项服务。它需要做的就是保持一个Dictionary,键是ViewModelType,值是ViewType。 Register方法添加到您的字典中,ShowWindow方法根据传入的ViewModel查找正确的视图,创建视图,设置DataContext,然后在其上调用Show。

大多数MVVM框架为您提供开箱即用的功能。例如,Caliburn有一个光滑的,只使用命名约定,在本框架中称为ViewLocator。这是一个总结的链接:http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introducing-caliburn-micro.aspx

另一方面,Cinch将其称为WPFUIVisualizerService,您可以在此处看到:http://www.codeproject.com/KB/WPF/CinchIII.aspx

这些应该有助于你滚动。


6
投票

好吧,开头的一句话是,“在代码隐藏中没有代码全部”实际上是一个“神话”。如果你想要务实,并且你看到拥有一些代码(尽可能少会更好),将使你的生活更轻松并解决你的问题,那么你应该去做。

但是,在这种情况下,实际上有一些松散耦合的方法来做到这一点。您可以拥有一个为您进行交互的服务。您从ViewModel启动与用户的交互,服务负责(例如,通过显示ChildWindow),并返回用户的响应。可以轻易地模拟该服务以进行测试。它可以单独测试。

也就是说,如果你想自己做事。如果你想要一个框架为你做繁重的工作,你可以查看Prism提供的InteractionRequest功能。这是关于adanced MVVM scenarios的MSDN文章,其中包括有关User Interaction Patterns的部分。这就是我的方式,它非常简单,优雅和直接。

希望这可以帮助 :)


3
投票

要进一步采用Matt的答案,您可以将所有视图都设置为用户控件。然后创建一个ViewContainer,它是一个包含数据模板的窗口(如您所述)。

然后,您只需将要打开的viewmodel发送到窗口服务,该窗口服务设置DataContext。然后该服务将打开窗口,contentcontrol将解析viewmodel的正确视图。

这意味着所有注册都在XAML中完成,窗口服务只知道如何做...打开和关闭窗口。


1
投票

这是一篇旧帖子,但也许这会帮助一路上的人:我使用MVVM,并将用于打开子窗口的事件从ViewModel提升回View。后面唯一的代码是处理事件,打开窗口,设置子窗口的所有者,这就是它。在viewmodel中,如果eventhandler为null,那么它不会被视图订阅而不会触发。 VM不知道该视图。代码也非常简单,只需几行。


0
投票

在这种情况下,View应该处理子窗口的打开。但是,ViewModel可能会驱动窗口的创建,但调用View来创建新的Windows。这将保存MVVM模式的逻辑:ViewModel具有“大脑”,但不参与特定的窗口创建。


0
投票

ViewModel仅用于呈现系统状态和UI逻辑。一个视图模型可以由多个视图引用。它不了解UI特定代码,如父/子关系,位置,布局,大小等。因此,最好使用ViewModel的状态更改事件或命令事件和事件参数在视图的代码隐藏中弹出子窗口。通过这种方式,您可以指定UI层中的父视图。

© www.soinside.com 2019 - 2024. All rights reserved.