问题描述
我一直在尝试使用的mvvm模式,并且在某些情况下,我一直在努力定义清晰的边界.在我的应用程序中,我有一个对话框,允许我创建与控制器的连接.对话框有一个ViewModel类,这很简单.但是,对话框还托管附加控制(由ContentTemplateSelector选择),这取决于正在连接的特定的控制器.该控件有自己的视图.
我遇到的问题是,当我按OK关闭对话框时,我需要实际创建所请求的连接,这需要在内部控制器特定的ViewModel类中捕获的信息.简单地让所有的控制器特定的ViewModel类实现了构建连接的公共接口,但如果内部视图模型真正负责这种结构?
我的一般问题是:有什么常见的设计模式,viewmodels应该如何与彼此交互,特别是当'父Vm需要从'孩子的VM中有所了解吗?
编辑:
我已经提出了一个比我最初思考的更清洁的设计,但我仍然不确定它是否是"正确的"方法.我有一些后端服务允许ContentTemplateElector查看控制器实例并伪神奇地找到要为连接构建器显示的控件.什么是困扰我的这就是我的顶级ViewModel必须看看DataContext为生成的控制,并将其投入到一个适当的界面,这似乎是一个坏主意(为什么该观点的DataContext有任何东西与创建连接有关?)
我缠绕在这样的东西(简化):
public interface IController { IControllerConnectionBuilder CreateConnectionBuilder(); } public interface IControllerConnectionBuilder { ControllerConnection BuildConnection(); }
i具有我的内视图class refting IControllerConnectionBuilder,并且控制器返回内视图.然后,顶级视图显示该IControllerConnectionBuilder(通过伪魔法机制).它仍然困扰我一点是我的内心视图模型执行建筑物,但至少现在我的顶级ViewModel不必知道脏细节(甚至不知道或关心可视化控制正在使用viewmodel).
如果有办法进一步清理这一点,我欢迎额外的想法.对我来说,它仍然不清楚它是多少责任为ViewModel拥有.
推荐答案
适用于ViewModels之间的交互的选项是直接绑定到观察者坐在ViewModel类之间的类.
其他推荐答案
我想你想让你的顶级ViewModel意识到NestedViewModel的存在,它从分层角度来看,主视图包含子视图.
在我看来,你的本能是对的,它对嵌套的ViewModel感到正确,以暴露在顶层上由用户操作启动的行为.相反,顶级ViewModel应该为其与之关联的视图提供行为.
但我会考虑将连接构造的责任移动到ICommand中,并通过顶级ViewModel暴露此命令.然后,您的主对话框中的OK按钮将绑定到此命令,并且该命令只会将其委托到顶级ViewModel,例如,执行时调用ViewModel.CreateConnection().
然后纯粹收集和将数据纯粹收集并将数据暴露于其NestedViewModel,以便由包含的ViewModel消耗,并且在不同的上下文中理论上更可用,需要相同的信息输入(如果有的话) - 假设您想要重新使用它来编辑已创建的连接.
唯一的皱纹是如果NestedViewModel不同类型的NestedViewModel暴露了一个完整的不同数据集.
例如,一个公开 hostname 和端口作为属性,另一个公开用户名和 password .
在这种情况下,您可能需要执行一些基础架构工作,以使您的顶级ViewModel.CreateConnection()仍然以清洁的方式工作.虽然如果您有少量嵌套的控制类型,但它可能不值得努力,并且简单NestedViewModel类型检查和演员可能就足够了.
这听起来是可行的吗?
其他推荐答案
我最近尝试了Unity(Microsoft Enterprise Library)来使用依赖项.当使用完全定义两个视图彼此不需要的接口时,这可能是要进行的路由. MEF将是依赖注入的另一个选择我知道.
hth
问题描述
I'm been experimenting with the oft-mentioned MVVM pattern and I've been having a hard time defining clear boundaries in some cases. In my application, I have a dialog that allows me to create a Connection to a Controller. There is a ViewModel class for the dialog, which is simple enough. However, the dialog also hosts an additional control (chosen by a ContentTemplateSelector), which varies depending on the particular type of Controller that's being connected. This control has its own ViewModel.
The issue I'm encountering is that, when I close the dialog by pressing OK, I need to actually create the requested connection, which requires information captured in the inner Controller-specific ViewModel class. It's tempting to simply have all of the Controller-specific ViewModel classes implement a common interface that constructs the connection, but should the inner ViewModel really be in charge of this construction?
My general question is: are there are any generally-accepted design patterns for how ViewModels should interact with eachother, particularly when a 'parent' VM needs help from a 'child' VM in order to know what to do?
EDIT:
I did come up with a design that's a bit cleaner than I was originally thinking, but I'm still not sure if it's the 'right' way to do this. I have some back-end services that allow a ContentTemplateSelector to look at a Controller instance and pseudo-magically find a control to display for the connection builder. What was bugging me about this is that my top-level ViewModel would have to look at the DataContext for the generated control and cast it to an appropriate interface, which seems like a bad idea (why should the View's DataContext have anything to do with creating the connection?)
I wound up with something like this (simplifying):
public interface IController { IControllerConnectionBuilder CreateConnectionBuilder(); } public interface IControllerConnectionBuilder { ControllerConnection BuildConnection(); }
I have my inner ViewModel class implement IControllerConnectionBuilder and the Controller returns the inner ViewModel. The top-level ViewModel then visualizes this IControllerConnectionBuilder (via the pseudo-magical mechanism). It still bothers me a little that it's my inner ViewModel performing the building, but at least now my top-level ViewModel doesn't have to know about the dirty details (it doesn't even know or care that the visualized control is using a ViewModel).
I welcome additional thoughts if there are ways to clean this up further. It's still not clear to me how much responsibility it's 'okay' for the ViewModel to have.
推荐答案
An option which works well for interaction between viewmodels is to bind directly to observer classes sitting between the viewmodel classes.
其他推荐答案
I think you want to make your top-level ViewModel aware of the existence of the NestedViewModel, it makes sense from a hierarchical standpoint, the master view contains the child view.
In my opinion, your instinct is right, it doesn't feel correct for the nested ViewModel to expose behaviours which are initiated by user actions on the top-level. Instead, the top-level ViewModel should be providing behaviors for the view it is associated with.
But I'd consider moving responsibility for connection construction into an ICommand, and exposing this command via your top-level ViewModel. The OK button on your master dialog you would then bind to this command, and the command would just delegate to the top-level ViewModel, for example, call ViewModel.CreateConnection() when it is executed.
The responsibility of your nested control is then purely collecting and exposing the data to its NestedViewModel, for consumption by the containing ViewModel, and it is theoretically more re-usable in different contexts that require the same information to be entered (if any) - let's say you wanted to re-use it for editing already-created connections.
The only wrinkle would be if the different types of NestedViewModel expose a radically different set of data.
For example, one exposes HostName and Port as properties, and another exposes UserName and Password.
In which case you may need to do some infrastructural work to have your top-level ViewModel.CreateConnection() still work in a clean manner. Although if you have a small amount of nested control types, it may not be worth the effort, and a simple NestedViewModel type-check and cast may suffice.
Does this sound viable?
其他推荐答案
I recently experimented with Unity (Microsoft Enterprise library) to use dependency injection. That might be a route to go when using interfaces that completely define what both viewmodels need to no from each other. MEF would be another option for dependency injection I'm aware of.
HTH