模板化形式的 MVVM 模式
在我的 silverlight 应用程序中,用户可以创建表单的多个模板。根据所选的模板,表单将按特定顺序显示一组视图。此外,如果模板上存在某些视图,则它们是“必需的”。客户端希望这些视图以弹出表单的形式显示,以便用户首先关注那些“必需”的视图,然后再转到表单上的其他视图。
现在,我发现自己打破了 MVVM 模式来满足此要求。这就是为什么... 1. ViewModel 可以从数据库读取模板,获取视图(使用 MEF),但要将它们添加到表单中,它需要知道布局网格的名称并将视图作为子项添加到该网格。这就像告诉 ViewModel 有关 UI 元素的信息,这是违反 MVVM 设计模式的。
- 对于必须在弹出窗口中显示的“必需”视图,viewModel 需要创建一个 ChildWindow 实例,向其中添加“必需”视图,然后显示 Childwindow。还处理关闭/关闭事件。
我确信我的方法是有缺陷的,但我无法找到一种方法将 UI 逻辑与业务逻辑完全分离。有人可以提供更好的方法吗?
谢谢。 一个
In my silverlight application the user can create multiple templates of a form. Depending upon the template selected, the form would display a set of views in a particular order. Furthermore, some of the views are "required" if present on the template. The client wants such views to be displayed in a popup form so the user focuses on just those "required" views first before moving onto the other views on the form.
Now, I see myself breaking MVVM pattern for this requirement. Here's why...
1. The ViewModel can read the template from the db, grab the views (using MEF) but to add them to the form, it would need to know the name of the layout grid and add views as a child to that grid. Thats like telling the ViewModel about the UI elements which is against MVVM design pattern.
- For the "required" views that must be displayed in a popup, the viewModel would need to create a ChildWindow instance, add the "required" views to it and then show the Childwindow. Also handles Closed/closing events.
I am sure my approach is flawed but am not able to figure out a way to cleanly separate the UI logic from the business logic here. Can someone provide a better approach.
Thanks.
A
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
恕我直言:这是另一种情况,只需将控制器添加到 MVVM 即可干净地解决所有问题。我们称之为 MVCVM(遗憾的是,它不等于有效的罗马数字):)
我们在最近的所有项目中成功使用的模式是仅在模块中注册控制器,并在启动时初始化它们。控制器非常轻/薄,是应用程序生命周期中唯一需要悬挂的东西监听或发送消息。然后,在他们的初始化方法中,他们注册他们需要拥有的任何东西(视图和视图模型等)。这种轻量级的内存中纯逻辑模式也使得应用程序更精简(例如,对于 WP7 更好)。
正如您所发现的,仅使用虚拟机的问题在于,最终您会遇到需要了解视图的情况(这是他们永远不应该了解的一件事)。
我们遵循的基本规则是:
最后两点是您永远不应该破坏或分离的点担忧消失了。
到目前为止,您的虚拟机需要直接访问数据库(不好),您的虚拟机需要获取视图(非常糟糕),并且需要您的虚拟机弹出另一个窗口(非常糟糕)。
想一想。您可能会(重新)将控制器引入您的 MVVM 应用程序。如果您想了解更多信息,请询问。
IMHO: This is yet another situation where simply adding controllers to MVVM would solve all the problems cleanly. We call it MVCVM (shame that does not equate to valid Roman Numerals) :)
The pattern we are using successfully on all recent projects is to register controllers only, in modules, and initialise them at startup. The controllers are very light/slim and the only thing that needs to hang around for the life of the app listening for, or sending, messages. In their initialise methods they then register anything they need to own (views and viewmodels etc). This lightweight logic-only-in-memory pattern makes for slimmer apps too (e.g. better for WP7).
The problem with just using VMs, as you have found, is that eventually you hit cases where they need to know about views (which is the one thing they should never know about).
The basic rules we follow are:
The last two points are the ones you should never break or separation of concerns goes out the window.
So far you have a need for your VM to access a database directly (bad), your VMs obtain the views (very bad) and a requirement for your VM to popup another window (insanely bad).
Give it some thought. You may come around to (re)introducing controllers to your MVVM apps. If you want more info just ask.
在我们的项目中,当需要完成 UI 特定的事情时,当需要在视图和视图模型之间进行通信时,我们一直遵循事件订阅机制。解决问题的一种方法是在视图模型上发布事件,并将视图列表作为事件参数。或者可能有一个维护此列表的属性,在视图模型上设置,并在属性更新时触发事件。在视图中,您可以订阅事件并将控件添加到布局根。这是可测试的解决方案,不会在视图模型中放置任何特定于视图的内容。
如果您可以自由使用 MVVM 框架,那么您可以尝试 PRISM 或 MVVMLight 之类的东西。 Prism提供了事件协商器,而MVVMLight提供了Messenger类,可以解耦视图和视图模型之间以及不同视图模型之间的通信。
In our project we have been following the event subscription mechanism when there is a need to communicate between the view and the view model when UI specific things need to be done. One way to solve your problem is to publish an event on the view model with the list of views as event argument. Or there could be a property which maintains this list, is set on the view model and the event fired when the property is updated. In the view you can subscribe to the event and add the controls to the layout root. This is testable solution and doesn't put anything view specific in the view model.
If you have the liberty of using MVVM framework then you can try something like PRISM or MVVMLight. Prism offers event agreegator while MVVMLight offers Messenger classes which can decouple the communication between view and view model as well as different view models.
这是我想到的解决方案。
1.使用带有与 ViewModel 关联的视图名称的元标记来装饰 ViewModel。
创建一个名为 ViewViewModel 的新类,它包含两个属性
在表单视图模型上,它负责将所有视图聚合在一起,并根据情况打开一个子窗口。添加三个属性
FormView 模型将实例化所需的视图模型,从其 MEF 元标记中收集每个视图模型的视图名称,并填充 FormView 和 ChildWindowView 属性。一旦 Form ViewModel 处理完请求并且填充了两个属性,如果 ChildWindow 不为空,它将使用 true 参数触发 ShowWindow 委托。
表单视图将执行以下操作
布局根将有一个绑定到 FormView 属性的 stackpanel。将有一个 IValueConverter 处理 FormViews List 中的每个条目。对于每个 ViewName,它查找并创建视图的实例。将 DataContext 设置为 ViewModel。
当引发 ShowChildWindow 操作时,表单视图中的代码隐藏量极少,它会创建并显示绑定到 ChildWindowViews 属性的 ChildWindow。 ChildWindow 属性使用相同的 IValueCOnverter 来创建请求的视图的实例。
听起来怎么样?请评论
Here's on solution that comes to my mind.
1.Decorate ViewModels with metatags that carry the View name the ViewModel is associated with.
Create a new Class called ViewViewModel that holds two properties
On the Form ViewModel, which is responsible for aggregating all the Views together and also bring up a childwindow depending upon the case. Add three properties
The FormView Model will instantiate required viewmodels, gather the View name from each viewmodel from its MEF metatag and populate the FormView and ChildWindowView properties. Once the Form ViewModel is done processing the request and the two properties have been populated it fires the ShowWindow delegate with true parameter if ChildWindow is not empty.
Form View will do the following
The Layout root will have a stackpanel bound to the FormView property. There will be an IValueConverter that processes each entry in FormViews List. For each ViewName, it finds and creates intance of the view. Sets the DataContext to the ViewModel.
When the ShowChildWindow action is raised, there's minimal code-behind in Form View that it creates and shows a ChildWindow that is bound to the ChildWindowViews property. ChildWindow property uses the same IValueCOnverter to create instances of requested Views.
How does that sound? Pls comment