2011-05-06 56 views
16

我一直在困惑这一段时间。我使用MVVM模式编写了一个相当大的WPF应用程序RibbonWindow。屏幕顶部有一个RibbonBar菜单,其余部分显示各种视图。某些视图包含其他视图,其中一些包含启动子视窗的按钮。在WPF中使用MVVM,我应该从后面的View代码或ViewModel启动子窗口吗?

到目前为止,我一直在使用View背后的代码来做这件事,但我知道这些文件在使用MVVM时应该是空的。我可以将子窗口启动代码移动到ViewModel,但后来我需要对主要的RibbonWindow(设置为子窗口所有者)的引用,这看起来不正确。

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

+4

我不同意查看代码背后的代码“应该是空的”。虽然有很多事情不应该在代码背后,但它仍然有价值。我将它用于特定于视图层的任何内容,例如管理控制焦点。我也用它来打开WPF中的后续Windows。 – 2011-05-07 14:42:26

+1

乔尔+1。 MVVM实现意味着VIEW SPECIFIC代码是应该位于代码背后的唯一代码。你的视图模型不应该处理像VSM状态变化这样的事情(除非这些变化可能是数据驱动的,在这种情况下,我会把它包装在虚拟机级暴露的行为或触发器中) – 2011-05-08 03:52:20

+0

感谢您的评论。他们真的为我清理了一些东西。 – Sheridan 2011-05-08 15:26:01

回答

19

我通常通过创建某种WindowViewLoaderService来处理这个问题。当你的程序初始化您注册窗口,并且带有代码是这样的你的ViewModels:

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

然后,当你能够例如调用到您的ViewModel此服务,并且所有你所引用的其他视图模型。例如,如果你在你的MainWindowViewModel你可能有这样的代码:

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

的WindowViewLoaderService会再看看什么查看与指定视图模型关联你传入。它将创建该视图,将其DataContext设置为您传入的ViewModel,然后显示该视图。

这样你的ViewModels永远不会知道任何视图。

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

莲花称其为WPFUIVisualizerService你可以在这里的行动看: http://www.codeproject.com/KB/WPF/CinchIII.aspx

这些应该帮助你滚。

+1

+1感谢您的详细回复。尽管我觉得这种方法很有趣,但我的应用程序已经非常成熟。视图通过使用未命名的'DataTemplate'' Resources'和'ContentControl'将视图模型链接到其ViewModel中ViewModel属性的'Content'属性。改变这一点会有很多工作要做,但这不是没有问题的......只要一天有更多的时间! – Sheridan 2011-05-07 00:29:00

+0

只是让你知道它通常不是一种或另一种方法。我几乎总是使用DataTemplates来做到这一点。然而,正如你所指出的 - 当你需要打开一个新的窗口(或者对话框)时,这不起作用。当你想到它时,你使用DataTemplate做的事情与使用ViewLocator做同样的事情。你基本上根据其DataType“注册”ViewModel到一个视图......反正只是想让你知道我认为你正确地做到了,唯一的问题是DataTemplates无法使用。 – 2011-05-07 04:04:45

+0

感谢您的补充评论 - 我认为我一定会深入研究这一点。 – Sheridan 2011-05-07 13:28:31

0

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

+0

但是,View如何打开一个新的'Window'? – Sheridan 2011-05-07 00:19:17

5

那么,首先要说的是,“在代码隐藏中没有任何代码”实际上是一个“神话”。如果你想要务实,并且你看到有一些代码(尽可能少些会更好),会让你的生活更轻松并解决你的问题,那么你应该去做。

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

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

希望这有助于:)

+1

+1感谢您的意见和有用的链接。我实际上调查了Prism,发现我不需要它提供的东西,并决定编写一个自定义的轻量级框架,但仍然试图让它正确。 – Sheridan 2011-05-07 00:33:32

+0

很高兴帮助。祝你好运与您的框架;) – AbdouMoumen 2011-05-07 00:40:04

3

采取马特的答案又进了一步,你可以有你的观点的是用户控制。然后创建一个ViewContainer,这是一个包含数据模板的窗口(如您所描述的)。

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

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

+0

+1感谢澄清。 – Sheridan 2011-05-07 13:30:09

1

这是一篇老帖子,但也许这会帮助别人:我使用MVVM,并提出了从ViewModel打开子窗口回到视图的事件。后面唯一的代码是处理事件,打开窗口,设置子窗口的所有者,这就是它。在视图模型中,如果事件处理程序为空,则它不会被视图订阅,也不会触发。 VM不知道该视图。代码非常简单,只需要几行。

0

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

相关问题