建模 M-V-VM






3.71/5 (8投票s)
本文试图提出一种解耦 M-V-VM ViewModel 对象的方法。
引言
构建基于 M-V-VM 的应用程序非常方便。本文旨在介绍一种通用的 View Model 解耦方法。
背景
使用 WPF 构建 UI 应用程序时,M-V-VM 是一种将数据与其表示形式解耦的绝佳机制。每个 UI 组件,无论是 Window、Page 还是 User Control,都有自己的 view model。大多数应用程序具有与 View 结构相对应的层次结构。因此,包含 User Control 的 Page 会将其 view model 保留为 User Control 的 View Model 作为类成员。当我想让控件中的某个动作对应用程序的其他部分产生影响时,我的问题就开始了。我过去的做法是在后代 View Model 中有一个“Parent
”属性。这在过去一直有效,直到我想在应用程序的新部分中重用该控件。然后我意识到使用这种方法限制了我的代码可重用性。我注意到解耦应该在 View Model 本身完成,而不仅仅是在 View 和 View Model 之间完成。那时我提出了“IViewModel
”解决方案。
我开始将不同的 View Model 视为独立的单元,因此不应该持有关于其发起者的任何知识。我的解决方案是创建 IViewModel
接口。使用此接口使 View Model 能够执行两件事:
- 通知 View Model 在其他 View Model 的 View 上发生的事件。
- 从应用程序的其他部分使用服务。
事件通知很容易理解,但是第二部分有点令人困惑。应用程序通常不是独立的,而是与外部范围(例如 DB 或远程服务)保持连接。我更喜欢为这些服务保留一个单点。
IVIewModel
IViewModel
是一个简单的接口:
/// <summary>
/// An interface which enables event routing via the view models
/// </summary>
public interface IViewModel
{
/// <summary>
/// A property which gets the View model's Parent
/// </summary>
IViewModel VMParent
{
get;
}
/// <summary>
/// A method which is used for handling events.
/// </summary>
/// <param name="sender">The original sender</param>
/// <param name="param">an attached parameter used for sending data</param>
/// <param name="viewModelEvent">an Enum which represents the name of
/// the event which needs to be taken care of</param>
void HandleEvent(IViewModel sender, object param,
ViewModelOperationsEnum viewModelEvent);
}
应用程序中的每个 ViewModel
类都实现此接口。如果 View model 只是其子项及其父项之间的管道,则 handle event 实现通常如下所示
public void HandleEvent(IViewModel sender,
object param, ViewModelOperationsEnum viewModelEvent)
{
if (VMParent != null)
{
VMParent.HandleEvent(sender, param, viewModelEvent);
}
}
使用应用程序
该应用程序由四个项目组成,客户端两个,服务器端两个。 应用程序运行时,将出现两个窗口,一个包含 TreeView
对象的 GUI 窗口和一个控制台窗口。 将这两个窗口并排放置。 打开树视图节点并解析这些节点。 您会注意到每个节点都向服务器发出请求。 这是在节点不了解服务器的任何信息的情况下完成的。
历史
- 2009 年 5 月 29 日:首次发布