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

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

问题描述

我花了相当长的一段时间,试图找到以下挑战一个完美的解决方案。我一直无法找到一个解决方案,这比解决问题是一个黑客。

我有一个视图,视图模型和模型的一个简单的设置。我将继续为解释起见,非常简单。


  • 模式标题 String类型的称为单属性。

  • 模式是在DataContext为查看

  • 查看有一个的TextBlock 这就是数据绑定到标题在模型。

  • 视图模型有一个名为方法保存(),将节省的模式服务器

  • 服务器可以推到所做的更改型号

到目前为止好。现在有两个调整,我需要为了保持模型同步与服务器进行。服务器的类型并不重要。只知道我需要调用保存(),以推动模型到服务器。

调整1:


  • Model.Title 属性将需要调用 RaisePropertyChanged()以转化为所做的更改模式服务器查看。这很好地工作,因为模式是在DataContext为查看

不是太糟糕了。

调整2:


  • 下一步是调用保存()保存在查看作出了<$ C $变动C>模式的服务器。这就是我会被卡住。我能处理的 Model.PropertyChanged 事件视图模型调用保存()当Model得到改变,但是这使得它呼应的服务器所做的更改。

我在寻找一个优雅和合理的解决方法,我愿意改变我的架构,如果它是有道理的。


解决方案

在过去,我已经写了一个支持活从多个位置数据对象的编辑应用程序:应用程序的多个实例可以在编辑同一个对象同时,当有人将更改应用于服务器的每个人都得到通知,并(在最简单的场景)立即看到这些变化。下面是它是如何设计的一个总结。

设置


  1. 视图的总是的绑定到的ViewModels。我知道这是一个很大的样板,而是直接绑定到模型是不能接受任何除了最简单的情形;它也没有在MVVM的精神。


  2. 的ViewModels拥有的唯一的推变化的责任。这显然​​包括推动改变到服务器,但它也可以包括推更改应用程序的其它部件。

    要做到这一点,的ViewModels可能想的克隆的他们包裹,使他们能够提供事务语义到应用程序的其他部分,因为它们提供给服务器的型号(例如,你可以选择何时推更改应用程序,这如果每个人都直接与同型号的实例),你不能做的其余部分。隔离这样的改变需要的还是的更多的工作,但它也开辟了强大的可能性(例如撤消更改很简单:就是不把他们)


  3. 的ViewModels对某种数据服务的依赖。数据服务是数据存储和消费者之间的坐和处理它们之间的所有通信的应用程序组件。每当一个视图模型克隆其型号也赞同适当的数据存储改变事件数据服务公开。

    这允许的ViewModels得到通知的变化,其他的ViewModels推到数据存储,并作出适当的反应,以他们的模式。有了适当的抽象,数据存储,也可以在所有的东西(例如,在特定应用程序的WCF服务)。


工作流程


  1. 创建一个视图模型和分配模型的所有权。它立即克隆模式,并公开该克隆到视图。其对数据服务的依赖,它告诉它要订阅通知更新这个特定的模型DS。视图模型不知道它是标识其模型(主密钥),但是它并不需要,因为这是DS的责任。


  2. 当用户完成编辑,他们与调用了VM命令查看交互。 VM,则调用到DS,推到它的克隆模式所做的更改。


  3. 在DS仍然存在的变化,还提出了一些通知更改为X型已作出的所有其他虚拟机感兴趣的事件;模型的新版本的事件参数的一部分提供。


  4. 这已经分配了相同型号的所有权现在知道,外部变化已经到达其他虚拟机。现在,他们可以决定如何更新视图具有手拼图的所有部分(以下简称previous版本的车型,这是克隆的,脏的版本,这是克隆;而当前版本,被推为事件参数的一部分)。


注释


  • 模型的 INotifyPropertyChanged的仅由视图中使用;如果视图模型想知道模型是否是脏,它可以随时克隆比较原始版本(如果它一直围绕不停,我建议如果可能的话)。

  • 视图模型将更改应用于服务器原子,这是很好的,因为它保证了数据存储始终保持一致的状态。这是设计的选择,如果你想要做的事情不同的另一种设计是比较合适的。

  • 服务器可以选择不提高模式改为事件视图模型,如果视图模型传递,这是负责这一变化这个作为参数的推改变的号召。即使不是这样,视图模型可以选择做什么,如果它看到模型的当前版本与它自己的克隆。

  • 有足够的抽象性,变化可以推到其它机器上运行一样容易,因为他们可以在你的shell推到其他意见等过程。

希望这有助于;如果需要,我可以提供更多的说明。

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.

  • 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

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.

Adjustment 1:

  • 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

Not too bad.

Adjustment 2:

  • 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.

解决方案

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.

Setup

  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.

  2. 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.

    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).

  3. 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.

    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).

Workflow

  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.

  2. 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.

  3. 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.

  4. 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).

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天全站免登陆