如何在 viewmodel 中访问 mvvm 模型中的控件?
Posted
技术标签:
【中文标题】如何在 viewmodel 中访问 mvvm 模型中的控件?【英文标题】:How can i access a control in mvvm model in viewmodel? 【发布时间】:2012-12-23 13:25:40 【问题描述】:我有一个 WPF 窗口,在那个窗口中我有一个网格。
我使用 M-V-VM 模型,我想在代码中(在视图模型中)动态地将 TextBox 添加到网格中
如何访问网格?
【问题讨论】:
在走这条路之前,我会确保它是绝对必要的,除非绝对没有其他选择,否则从视图模型访问视图通常是不好的做法。 @BenjaminPaul 所说的。使用 MVVM 时,您无需从 ViewModel 添加控件。使用绑定来完成这项工作。 是的,我知道,这正是我的意思。然而,我有时需要在视图模型中获得对控件的引用,以适应不支持常规绑定的控件。这也是我所指的场景。 【参考方案1】:使用 Supervising Controller 模式。
阅读:
CaliburnMicro MVVM 框架的示例实现如下所示(对所有其他框架都一样——或者如果你自己做 MVVM,你也可以手动做):
http://drc.ideablade.com/devforce-2012/bin/view/Documentation/cocktail-tutorial-talk-to-view
示例:
1) 定义接口IView
,其中ViewModel
(VM
) 将使用所需的方法与View
对话
public interface IView
void AddTextBoxToGrid();
2) 从你的IView
继承View
后面的代码并实现IView.AddTextboxToGrid()
方法
public partial class View: IView
public void AddTextBoxToGrid()
// implement here your custom view logic using standard code behind;
3) 将IView
类型的属性添加到您的VM
public class ViewModel
public IView View get; set;
4) 将VM
上的View
属性设置为View
的实例 为IView
例如在后面的代码中:
DataContext.View = this as IView;
或者在 Caliburn 中你可以使用 IScreen.OnViewAttached 覆盖方法)
public partial class View: IView
public View()
// access you VM by the strategy of your framework or choice - this example is when you store your VM in View's DataContext
(DataContext as ViewModel).View = this as IView;
public void AddTextBoxToGrid()
// implement here your custom view logic using standard code behind;
5) 在您的VM
致电IView.AddTextboxToGrid()
public class ViewModel
public IView View get; set;
public void AddTextBoxToGrid()
if (View == null) return;
View.AddTextBoxToGrid()
【讨论】:
最好使用构造函数注入将IVew
实例发送到ViewModel
(我的意思是,ViewModel
类的构造函数应该接受IView
实例)。
需要强调的是,在视图中从 viewmodel 创建依赖也不是最纯粹的 mvvm。当您使用(DataContext as SomeViewModel)
时,您的视图将依赖于SomeViewModel
,这可能是不可取的。你怎么看?
@MohammadDehghan:您将如何使用 Caliburn 实现这一点?
非常明确的答案。在保持 MVVM 模式的同时还有其他选择吗?
@heltonbiker 为什么不受欢迎?视图总是知道视图模型(请记住,所有绑定都引用视图模型的属性)并且添加一个直接依赖项不会以任何其他方式造成伤害。什么是“禁止”是视图模型直接知道视图。【参考方案2】:
您应该将创建代码移至 View,并且 ViewModel 应该在应该调用它时通知视图。
【讨论】:
【参考方案3】:您还可以在视图后面的代码中使用视图的 DataContext(即 ViewModel),并将文本框添加到那里的网格中。那会更有意义。
如果您在 XAML 文件中为网格命名,您将能够立即在后面的代码中访问网格。
【讨论】:
【参考方案4】:如果您使用的是 Caliburn Micro,请执行以下步骤:
使ViewModel继承自接口IViewAware
;你要实现这个接口的两个方法AttachView和GetView。
定义一个 View 类型的变量来获取对 View 的引用
详见下文:
private SomeViewClass v;
public void AttachView(object view, object context = null)
v = view as BomView;
if (ViewAttached != null)
ViewAttached(this,
new ViewAttachedEventArgs() Context = context, View = view );
public object GetView(object context = null)
return v;
稍后您可以通过 v 访问视图上的单个元素,例如 v.txtName="John";等等……
【讨论】:
BomView = SomeViewClass。视图类的名称。以上是关于如何在 viewmodel 中访问 mvvm 模型中的控件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 MVVM 和 Caliburn Micro 在多个 ViewModel 中使用模型中的数据
MVVM:修改模型,如何正确更新 ViewModel 和 View?