繁体   English   中英

MVVM Datagrid已从视图和模型更新

[英]MVVM Datagrid updated from View and Model

我有一个数据网格,它绑定到实现INotifyPropertyChanged的Item对象。

在ViewModel中,我订阅来自外部设备服务的更改,该服务会更新Item对象。 数据网格是可编辑的,因此也可以从视图中更改项目。 该值应写入设备,但尚未在视图中更新,因为设备写入可能会失败。 如果成功,设备将发出一个我已经订阅的事件。

我有些担心。

从ViewModel或Item对象到设备服务的哪里调用写? 如何确保编辑后直到从设备接收事件之前,“恢复”在数据网格中显示的值?

一些想法

  1. 如果它是Item对象,那么Item对象不再是DTO,而是我认为的ViewModel。 因此,我将为同一视图(用户控件)提供两个视图模型。 一种用于用户控制,另一种用于数据网格中的项目。 这与我对视图模型的理解不符。 但是,也许是错的吗? 项又如何知道该值是从视图(由用户)还是从视图模型(由设备服务)更新的?

  2. ViewModel订阅Item对象上的PropertyChanged。 要检测View是否更改了值,当从服务获取事件时,ViewModel可以退订PropertyChanged或设置标志。 看起来很笨拙,但可以使用。 也许我应该设置两个属性:ViewValue和ServiceValue。 ViewModel应该更新ServiceValue并订阅ViewValue,在读取ViewModel之后,ViewModel可以将其中的ViewValue还原为ServiceValue。

  3. 视图处理CellEditEnding并通知视图模型

关于要点1):是,使用ViewModel绑定到UI而不是DTO。 这是帮助从MVVM中的视图中分离数据的主要思想。

关于第2点和第3点,建议您在ViewModels上实现IEditableObject接口,可能在通用的基类上实现。

该接口提供了BeginEdit(), CancelEdit(), and EndEdit() 使用这些方法可以使您对何时修改哪个对象以及何时将这些更改提交到服务或数据库具有清晰可读的控制。

同样,实现这些方法还为您提供了一种机制来处理这些不同的数据版本,例如提到的“ ViewValue”和“ ServiceValue”。 你可以创建ServiceValue的本地副本作为一个回退时方法BeginEdit()如果方法被调用和调用这个地方回退值CancelEdit()被调用。 如果EndEdit()EndEdit()值提交回服务的时间,然后成功将当前值存储在该本地临时值中作为新的后备值。

编辑以添加第1点的答案)

我不确定这是否是“最佳实践”,但是至少这是我们在工作中会做到的。

我们通常以这样的方式组织ViewModel:每个视图有一个ViewModel,其中包含某个视图的所有信息。 我们将此称为“主ViewModel”。 如果我们需要视图层次结构,则可以实现遵循相同层次结构的ViewModels层次结构。

在像您这样的情况下,我们会将DataGrid放入主视图中包含的另一个UserControl中。 主ViewModel将保存另一个ViewModel,该ViewModel再次保存DataGrid所需的数据。 该ViewModel将设置为该DataGrid-UserControl的DataContext。 这样,您仍然可以保留一个干净的每个视图一个ViewModel的分隔。

然后可以通过Templates来配置DataGrid中数据的其他格式。

1)由您的外部数据服务更新您的DTO类将不会使其纳入视图模型。 DTO是模型或业务对象层的一部分。 它的工作是在表示(视图和视图模型)和存储层(数据库)之间传送数据,并执行验证(如果需要)。 由外部(非视图)服务进行更新完全在其作用范围之内。 您对每个窗口或用户控件一个VM的评论是正确的-VM是基于每个视图而不是每个控件分配的(尽管可以将同一VM类重用于多个视图)。 您应该在虚拟机上具有该视图绑定到的DTO实例。 这就是VM的工作-组织,管理和呈现视图的模型所需部分。

如您在问题中提到的,要让DTO知道更新的来源,您可以添加一个标志以指示更新是来自视图还是来自服务,并根据需要进行设置。 或者,您可以使服务通过公共方法更新DTO,并使视图直接绑定到属性。 根据您的设计,此选项可能比设置标志的可行性要差得多。

2)如另一个答案中所述, IEditableObject是一个不错的选择。 不需要在DTO上同时备份服务和查看数据,并且可以有效地将对象的大小增加三倍(假定它是一个薄包装器,如果是DTO,则应该是它)。 如果您确实需要还原到数据的任一版本的能力-例如,由于您为用户提供了选择还原时要使用哪个版本的选项,则将多余的数据保留在VM上而不是模型上。 我想不出您需要不涉及某种演示或用户交互决策的选项的原因。 数据驱动的还原应设计为始终具有确定性。

3)同样, IEditableObject 视图不应该通知视图模型; 它应该对虚拟机一无所知(没有任何引用)。 这将放松两层之间的耦合,并增加应用程序的灵活性。 我通常通过拥有专门用于处理视图的控制器类来实现此目的。 打开视图时,它将创建一个新的VM实例,并将该视图的DataContext指向该实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM