我有多个视图(用户控件),每个视图都有自己的ViewModel
。要在它们之间导航,我正在使用按钮。按钮显示来自相应视图模型的图像和文本,还需要列和行(因为有10个视图:10列,每行有不同的行数)。
现在按钮是动态创建 (我为此创建了一个Navigator
控件)对于视图模型我有基类来保存文本,图像,列和行。可用的观看次数会有所不同(取决于用户级别和某些设置),这就是我需要控制的原因。
问题:我的控件如何从视图模型中获取数据?
现在我有接口INavigator
,在(lol)控件本身中定义。视图模型实现它。我可以反过来,让我的控制知道关于视图模型的。两者都看错了。
有一个Navigator
控件,可以说,Items
绑定到视图模型列表。它可以将每个视图模型转换为INavigator
或ViewModelBase
(所有页面都通用)以获取特定的视图模型图像,文本,列和行。所以任一视图模型都知道控制(实现INavigator
)或控制知道ViewModelBase
..这是一个问题,两个解决方案绑定严格控制和视图模型,这在{{1}中是不好的}。
示意性地
答案 0 :(得分:3)
您绘制图表的方式回答了您自己的问题,即如何为此构建代码。
你需要的是一个虚拟机(让我们称之为MainVM
),其中包含ObservableCollection<VMBase>
个其他虚拟机(使用你的基本类型,以便他们都可以幸福地生活在同一个集合中)。 / p>
您的视图需要ItemsControl
(绑定到您的ObservableCollection<VMBase>
),您只需使用VMBase类型公开的属性为Button指定DataTemplate
。在按钮中设置Command
属性以呼叫SwitchCommand
,CommandParameter
设置为项目本身(即{Binding .}
)。
您的视图还需要ContentControl
绑定到SelectedVM
上可以填充的MainVM
媒体资源。
实施SwitchCommand
以根据CommandParameter中的值设置SelectedVM
属性。
public void ExecuteSwitchCommand(object parameter)
{
var vmBase = parameter as VMBase;
if (vmBase != null)
SelectedVM = vmBase;
}
此处提到的所有属性都应该INotifyPropertyChanged
启用,以便View在更改和更新UI时进行注册。
要获取ContentControl
的不同UI,请将每种特定VM类型的特定于类型的DataTemplates添加到View的Resources文件中(或者如果您很聪明并且正在构建自定义插件框架,合并资源字典)。
很多人忘了MVVM,重点是View与ViewModel有目的地分离,这意味着你可以为一个ViewModel提供很多视图,这就是它所展示的。
答案 1 :(得分:2)
我觉得将MVVM视为一种自上而下的方法是最容易的...... View了解它的ViewModel,ViewModel知道它的模型,但Model不知道它的ViewModel和ViewModel不知道它的视图。
我还发现了一种最容易使用的View-first开发方法,因为XAML中的UI开发是静态的(必须是)。
我认为很多人都会把每个组件(M,V,VM)独立且可替换的,包括在内,但我和我一起。我们慢慢得出结论,这只会适得其反。
从技术上讲,确定你可以变得非常复杂并使用IoC容器,创建一些将View类型绑定到ViewModel类型的ViewLocator对象,但是......除了更多的混淆之外,究竟是什么让你获益?因为现在你已经失去了设计时间的支持,尤其是在其他方面,它使老实说更难(因为我已经在某一点上完成了这一点);并且仍绑定到视图中的特定视图模型界面或在运行时创建绑定。为什么会使它复杂化?
This article is a good read,第一个注意:明确谈到了View与ViewModel。希望它能帮助你得出自己的结论。
要直接回答您的问题,我认为让您的ViewModel实现某种类型的INavigator
接口可能是理想的。请记住,您的虚拟机是“粘合剂”。在您的视图和模型/业务逻辑之间,它的工作是将业务数据转换为您的视图可以使用的数据,因此它存在于UI和业务层之间。
这就是Messengers and View Services之类的东西,这是ViewModel上的导航器服务可以很好地适应的原因。
答案 2 :(得分:1)
我认为这种设计导致了一种无路可走的局面。
我相信创建一个自定义按钮控件,其中dependency properties
绑定图像,行和列实际上为它所驻留的页面提供了一种方式来获取它们的信息;它们是否是动态创建的。
继续这个想法。没有MVVM逻辑应用于自定义控件,该控件包含完成其工作所需的内容,并且通过所提到的依赖项属性。按钮的任何功能都应该通过命令来完成;所有这些都使按钮数据驱动并足够强大,可以在MVVM方法中使用。
问题:我的控件如何从视图模型中获取数据?
应只有一个viewmodel,它是控件所在的页面。控件只是绑定到最终驻留在该VM上的信息。它是如何实现的,这取决于程序员。如果该按钮将包含状态数据,那么它将从其依赖属性以双向方式绑定回项,它将被绑定。
通过将VM保持在按钮之外,并且只有一个VM是分离和维护数据的最佳方式。除非我真的在这里错过了什么......
答案 3 :(得分:1)
在这里和其他人一样,我觉得实际理解你的要求有点难,所以这很普遍。问题标题的答案很简单:Control始终通过绑定从ViewModel获取数据。您将Control的DataContext
设置为相应的ViewModel,然后从那里保持ViewModel和Control同步:
如果您向视图添加ItemsControl
个按钮,则会向ViewModel添加ObservableCollection<ButtonViewModel>
并将ItemsSource
的{{1}}绑定到此。
如果您允许用户向View动态添加内容,则执行该操作的实际代码将驻留在ViewModel中,例如当用户单击“添加按钮”按钮时,您使用ItemsControl
属性调用ViewModel方法,该方法将Command
添加到集合中,View将自动反映您的更改。
确实存在无法在ViewModel中专门编码的复杂案例,我发现行为是那里缺少的链接,但是当你向我展示具体案例时我会深入研究。
如果您想获得一个有效的示例,请提供尽可能多的代码,并准确了解它应该做什么。