MVVM:绑定到模型,同时保持模型与服务器版本同步 [英] MVVM: Binding to Model while keeping Model in sync with a server version

查看:18
本文介绍了MVVM:绑定到模型,同时保持模型与服务器版本同步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我花了相当多的时间来尝试为以下挑战找到一个优雅的解决方案.我一直无法找到解决问题的解决方案.

I've spent quite some time to try and find an elegant solution for the following challenge. I've been unable to find a solution that's more than a hack around the problem.

我有一个简单的视图、视图模型和模型设置.为了解释起见,我将保持非常简单.

I've got a simple setup of a View, ViewModel and a Model. I will keep it very simple for the sake of explanation.

  • Model 有一个名为 Title 的 String 类型的属性.
  • ModelView 的 DataContext.
  • View 有一个 TextBlock 数据绑定到模型上的 Title.
  • ViewModel 有一个名为 Save() 的方法,它将把 Model 保存到一个 Server
  • Server 可以推送对 Model
  • 所做的更改
  • The Model has a single property called Title of type String.
  • The Model is the DataContext for the View.
  • The View has a TextBlock thats databound to Title on the Model.
  • The ViewModel has a method called Save() that will save the Model to a Server
  • The Server can push changes made to the Model

到目前为止一切顺利.现在我需要进行两项调整,以使模型与 Server 保持同步.服务器的类型并不重要.只知道我需要调用 Save() 以便将模型推送到 Server.

So far so good. Now there are two adjustments I need to make in order to keep the Model in sync with a Server. The type of server is not important. Just know that I need to call Save() in order to push the Model to the Server.

调整 1:

  • Model.Title 属性将需要调用 RaisePropertyChanged() 以转换 Model 所做的更改服务器View.这很好用,因为 ModelView
  • 的 DataContext
  • The Model.Title property will need to call RaisePropertyChanged() in order to translate changes made to the Model by the Server to the View. This works nicely since the Model is the DataContext for the View

还不错.

调整 2:

  • 下一步是调用 Save() 以保存从 ViewServer 上的 Model 所做的更改代码>.这就是我卡住的地方.我可以处理 ViewModel 上的 Model.PropertyChanged 事件,该事件在模型更改时调用 Save(),但这会使其回显服务器所做的更改.
  • Next step is to call Save() to save changes made from the View to the Model on the Server. This is where I get stuck. I can handle the Model.PropertyChanged event on the ViewModel that calls Save() when the Model gets changed but this makes it echo changes made by the Server.

我正在寻找一种优雅且合乎逻辑的解决方案,并且愿意在合理的情况下更改我的架构.

I'm looking for an elegant and logical solution and am willing to change my architecture if it makes sense.

推荐答案

过去我写过一个支持live"的应用程序.从多个位置编辑数据对象:应用程序的多个实例可以同时编辑同一个对象,当有人将更改推送到服务器时,其他所有人都会收到通知,并且(在最简单的情况下)会立即看到这些更改.下面是它的设计摘要.

In the past I 've written an application that supports "live" editing of data objects from multiple locations: many instances of the app can edit the same object at the same time, and when someone pushes changes to the server everyone else gets notified and (in the simplest scenario) sees those changes immediately. Here's a summary of how it was designed.

  1. 视图总是绑定到视图模型.我知道它有很多样板文件,但在最简单的情况下,直接绑定到模型是不可接受的;这也不符合 MVVM 的精神.

  1. Views always bind to ViewModels. I know it's a lot of boilerplate, but binding directly to Models is not acceptable in any but the simplest scenarios; it's also not in the spirit of MVVM.

ViewModels 唯一负责推动更改.这显然包括将更改推送到服务器,但也可能包括将更改推送到应用程序的其他组件.

ViewModels have sole responsibility for pushing changes. This obviously includes pushing changes to the server, but it could also include pushing changes to other components of the application.

为此,ViewModels 可能希望克隆它们包装的模型,以便它们可以在向服务器提供事务时向应用程序的其余部分提供事务语义(即您可以选择何时推送更改应用程序的其余部分,如果每个人都直接绑定到同一个 Model 实例,则您无法执行此操作).隔离这样的更改需要仍然更多的工作,但它也开辟了强大的可能性(例如,撤消更改是微不足道的:只是不要推动它们).

To do this, ViewModels might want to clone the Models they wrap so that they can provide transaction semantics to the rest of the app as they provide to the server (i.e. you can choose when to push changes to the rest of the app, which you cannot do if everyone directly binds to the same Model instance). Isolating changes like this requires still more work, but it also opens up powerful possibilities (e.g. undoing changes is trivial: just don't push them).

ViewModel 依赖于某种数据服务.数据服务是一个应用程序组件,它位于数据存储和使用者之间,并处理它们之间的所有通信.每当 ViewModel 克隆其模型时,它也会订阅适当的数据存储已更改".数据服务公开的事件.

ViewModels have a dependency on some kind of Data Service. The Data Service is an application component that sits between the data store and the consumers and handles all communication between them. Whenever a ViewModel clones its Model it also subscribes to appropriate "data store changed" events that the Data Service exposes.

这允许 ViewModels 收到他们的"更改的通知.其他 ViewModel 已推送到数据存储并做出适当反应的模型.通过适当的抽象,数据存储也可以是任何东西(例如,该特定应用程序中的 WCF 服务).

This allows ViewModels to be notified of changes to "their" model that other ViewModels have pushed to the data store and react appropriately. With proper abstraction, the data store can also be anything at all (e.g. a WCF service in that specific application).

工作流程

  1. 创建了一个 ViewModel 并分配了一个模型的所有权.它立即克隆模型并将此克隆公开给视图.依赖于数据服务,它告诉 DS 它想要订阅更新此特定模型的通知.ViewModel 不知道是什么标识了它的 Model(主键"),但它不需要,因为这是 DS 的责任.

  1. A ViewModel is created and assigned ownership of a Model. It immediately clones the Model and exposes this clone to the View. Having a dependency on the Data Service, it tells the DS that it wants to subscribe to notifications for updates this specific Model. The ViewModel does not know what it is that identifies its Model (the "primary key"), but it doesn't need to because that's a responsibility of the DS.

当用户完成编辑时,他们会与调用 VM 上的命令的视图进行交互.然后 VM 调用 DS,推送对其克隆模型所做的更改.

When the user finishes editing they interact with the View which invokes a Command on the VM. The VM then calls into the DS, pushing the changes made to its cloned Model.

DS 保留更改并另外引发一个事件,通知所有其他感兴趣的 VM 已对 Model X 进行更改;新版本的模型作为事件参数的一部分提供.

The DS persists the changes and additionally raises an event that notifies all other interested VMs that changes to Model X have been made; the new version of the Model is supplied as part of the event arguments.

其他已分配相同模型所有权的 VM 现在知道外部更改已经到来.他们现在可以决定如何更新具有手头所有拼图部分的视图(模型的先前"版本,已克隆;脏"版本,即克隆;以及当前"版本).版本,作为事件参数的一部分推送).

Other VMs that have been assigned ownership of the same Model now know that external changes have arrived. They can now decide how to update the View having all pieces of the puzzle at hand (the "previous" version of the Model, which was cloned; the "dirty" version, which is the clone; and the "current" version, which was pushed as part of the event arguments).

注意事项

  • 模型的 INotifyPropertyChanged 仅被视图使用;如果 ViewModel 想知道 Model 是否脏",它总是可以将克隆与原始版本进行比较(如果它一直存在,我建议如果可能的话).
  • ViewModel 以原子方式将更改推送到服务器,这很好,因为它确保数据存储始终处于一致状态.这是一种设计选择,如果您想以不同的方式做事,另一种设计会更合适.
  • 服务器可以选择不提出模型已更改";如果 ViewModel 将 this 作为参数传递给推送更改",则负责此更改的 ViewModel 的事件.称呼.即使没有,ViewModel 也可以选择什么都不做,如果它看到当前"模型的版本与其自己的克隆相同.
  • 通过足够的抽象,可以将更改推送到其他机器上运行的其他进程,就像推送到 shell 中的其他视图一样容易.
  • Notes

    • The Model's INotifyPropertyChanged is used only by the View; if the ViewModel wants to know whether the Model is "dirty", it can always compare the clone to the original version (if it has been kept around, which I recommend if possible).
    • The ViewModel pushes changes to the Server atomically, which is good because it ensures that the data store is always in a consistent state. This is a design choice, and if you want to do things differently another design would be more appropriate.
    • The Server can opt to not raise the "Model changed" event for the ViewModel that was responsible for this change if the ViewModel passes this as a parameter to the "push changes" call. Even if it does not, the ViewModel can choose to do nothing if it sees that the "current" version of the Model is identical to its own clone.
    • With enough abstraction, changes can be pushed to other processes running on other machines as easily as they can be pushed to other Views in your shell.
    • 希望这有帮助;如果需要,我可以提供更多说明.

      Hope this helps; I can offer more clarification if required.

      这篇关于MVVM:绑定到模型,同时保持模型与服务器版本同步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆