18

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

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

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

4

6 回答 6

20

我通常通过创建某种 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。它将创建该视图,将其 DataContext 设置为您传入的 ViewModel,然后显示该视图。

这样,您的 ViewModel 就永远不会知道任何视图。

您可以很容易地推出自己的这些服务之一。它需要做的就是保留一个字典,键是您的 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

这些应该可以帮助您滚动。

于 2011-05-06T21:12:30.090 回答
6

好吧,首先要说的是,“代码隐藏中根本没有代码”实际上是一个“神话”。如果您想务实,并且看到拥有一些代码(越少越好)将使您的生活更轻松并解决您的问题,那么您应该这样做。

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

也就是说,如果你想自己做事。如果您想要一个框架为您完成繁重的工作,您可以查看PrismInteractionRequest提供的功能。这是 MSDN 文章,其中讨论了高级 MVVM 场景,其中包括有关用户交互模式的部分。我就是这样做的,它非常简单、优雅和直接。

希望这可以帮助 :)

于 2011-05-06T21:36:31.220 回答
3

为了让马特的回答更进一步,您可以让所有视图都成为用户控件。然后创建一个 ViewContainer,这是一个包含数据模板的窗口(如您所述)。

然后,您只需将希望打开的视图模型发送到设置 DataContext 的窗口服务。然后服务将打开窗口,内容控件将为视图模型解析正确的视图。

这意味着所有注册都在 XAML 中完成,并且窗口服务只知道如何执行此操作...打开和关闭窗口。

于 2011-05-07T12:46:02.133 回答
1

这是一篇旧文章,但也许​​这会帮助某人:我使用 MVVM,并引发事件以从 ViewModel 打开子窗口回到 View。后面的唯一代码是处理事件、打开窗口、设置子窗口的所有者,仅此而已。在视图模型中,如果事件处理程序为空,则视图不会订阅它并且不会触发。VM 不知道该视图。代码也很简单,只需要几行。

于 2016-11-13T13:03:11.160 回答
0

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

于 2011-05-06T21:01:27.533 回答
0

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

于 2017-05-25T07:52:34.157 回答