首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MVVM:在与服务器版本保持模型同步的同时绑定到模型

MVVM:在与服务器版本保持模型同步的同时绑定到模型
EN

Stack Overflow用户
提问于 2012-05-03 18:24:24
回答 5查看 20K关注 0票数 33

我花了相当长的时间试图为下面的挑战找到一个优雅的解决方案。我一直找不到解决问题的办法。

我有一个简单的设置视图,ViewModel和一个模型。为了解释起见,我会把它写得很简单。

  • Model有一个名为String类型的Title的属性。
  • ModelView的DataContext。
  • View有一个TextBlock,该数据库可以在模型上指向Title
  • ViewModel有一个名为Save()的方法,它可以将Model保存到一个Server,可以将更改推到Model

上。

到目前一切尚好。现在,我需要做两个调整,以使模型与Server保持同步。服务器的类型并不重要。只需知道我需要调用Save()才能将模型推送到Server.

调整1:

  • -- Model.Title属性需要调用RaisePropertyChanged(),以便将ServerModel所做的更改转换为View。这很好,因为View

Model是DataContext

不算太坏。

调整2:

  • 下一步是调用Save()以保存从ViewServer上的Model所做的更改。这就是我被困的地方。当模型被更改时,我可以在ViewModel上处理调用Save()的ViewModel事件,但这使它与Server.

所做的更改相呼应。

我正在寻找一个优雅而合乎逻辑的解决方案,如果有意义的话,我愿意改变我的架构。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2012-05-04 08:34:03

过去,我曾编写过一个应用程序,它支持多个位置的数据对象“实时”编辑:应用程序的许多实例可以同时编辑同一个对象,当有人向服务器推送更改时,其他所有人都会得到通知,并且(在最简单的情况下)立即看到这些更改。下面简要介绍一下它是如何设计的。

设置

  1. 视图总是绑定到ViewModels。我知道这是很多样板,但是直接绑定到模型在任何最简单的场景中都是不可接受的;它也不符合MVVM.

的精神。

  1. ViewModels完全负责推动变革。这显然包括将更改推送到服务器,但也可以包括将更改推送到应用程序的其他组件。

要做到这一点,ViewModels可能希望克隆它们包装的模型,这样它们就可以为应用程序的其余部分提供事务语义,就像它们提供给服务器一样(也就是说,您可以选择何时将更改推送到应用程序的其余部分,如果每个人都直接绑定到同一个Model实例,则不能这样做)。隔离这样的更改需要做更多的工作,但它也提供了强大的可能性(例如,取消更改是微不足道的:只是不要推它们)。

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

这允许ViewModels被告知对“他们的”模型的更改,而其他ViewModels已经将这些更改推送到数据存储中,并做出了适当的反应。有了适当的抽象,数据存储也可以是任何东西(例如,特定application).中的WCF服务)。

工作流程

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

的责任。

当用户完成编辑时,

  1. 与视图交互,该视图调用VM上的命令。VM然后调用DS,将对其克隆模型所做的更改推送给它的.

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

  1. 被分配给同一模型所有权的其他VM现在知道外部更改已经到来。现在,他们可以决定如何更新视图,将所有的拼图都放在手上(模型的“先前”版本已经被克隆;“脏”版本是克隆的;“当前”版本是作为事件参数的一部分被推送的)。

备注

possible).

  • The
  • 模型的INotifyPropertyChanged只供视图使用;如果ViewModel想知道模型是否“脏”,它总是可以将克隆与原始版本进行比较(如果它一直在附近,我建议如果 ViewModel原子地将更改推送到服务器,这很好,因为它确保数据存储始终处于一致状态。这是一种设计选择,如果您想以不同的方式处理事情,另一种设计将是更多的appropriate.
    • The服务器可以选择不为负责此更改的ViewModel引发“模型更改”事件,如果ViewModel将this作为参数传递给“推送更改”调用。即使没有,如果ViewModel看到模型的“当前”版本与它自己的克隆版本相同,它可以选择什么也不做。具有足够抽象性的
    • 可以将更改推送到其他机器上运行的其他进程,就像它们可以被推送到shell中的其他视图一样容易。

希望这有帮助;如果需要的话,我可以提供更多的澄清。

票数 75
EN

Stack Overflow用户

发布于 2012-05-04 08:52:28

我建议在MVVM组合中添加控制器(MVCVM?)以简化更新模式。

控制器侦听较高级别的更改,并在模型和ViewModel之间传播更改。

保持事物清洁的基本规则是:

  • ViewModels只不过是一个简单的容器,可以保存一定形状的数据。他们不知道数据从哪里来,也不知道它在哪里,displayed.
  • Views (通过绑定到视图模型)显示某种形状的数据。他们不知道数据来自哪里,只知道如何显示数据。
  • 模型提供真实的数据。他们不知道consumed.
  • Controllers实现逻辑在哪里。比如在VM中为ICommands提供代码,侦听数据的变化等等。它们从模型中填充VM。让他们监听VM更改并更新Model.

是有意义的。

正如在另一个答案中提到的,您的DataContext应该是VM (或它的属性),而不是模型。针对DataModel,很难将关注点分离开来(例如,用于测试驱动的开发)。

大多数其他解决方案都将逻辑放在ViewModels中,这是“不正确的”,但我看到控制器的好处一直被忽视。该死的MVVM首字母缩写!:)

票数 7
EN

Stack Overflow用户

发布于 2012-05-04 06:49:09

只有当模型实现INotifyPropertyChanged接口时,才能直接查看绑定模型。(例如,由实体框架生成的模型)

模型实现INotifyPropertyChanged

你能做到的。

代码语言:javascript
复制
public interface IModel : INotifyPropertyChanged //just sample model
{
    public string Title { get; set; }
}

public class ViewModel : NotificationObject //prism's ViewModel
{
    private IModel model;

    //construct
    public ViewModel(IModel model)
    {
        this.model = model;
        this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
    }

    private void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Title")
        {
            //Do something if model has changed by external service.
            RaisePropertyChanged(e.PropertyName);
        }
    }
    //....more properties
}

ViewModel作为DTO

如果模型实现了INotifyPropertyChanged(这取决于),那么在大多数情况下,您可以使用它作为DataContext。但在DDD中,大多数MVVM模型被认为是EntityObject模型,而不是一个真正的域模型。

更有效的方法是使用ViewModel作为DTO。

代码语言:javascript
复制
//Option 1.ViewModel act as DTO / expose some Model's property and responsible for UI logic.
public string Title
{
    get 
    {
        // some getter logic
        return string.Format("{0}", this.model.Title); 
    }
    set
    {
        // if(Validate(value)) add some setter logic
        this.model.Title = value;
        RaisePropertyChanged(() => Title);
    }
}

//Option 2.expose the Model (have self validation and implement INotifyPropertyChanged).
public IModel Model
{
    get { return this.model; }
    set
    {
        this.model = value;
        RaisePropertyChanged(() => Model);
    }
}

上面的两个ViewModel属性都可以用于绑定,而不是破坏MVVM模式(模式!=规则)--这确实取决于。

还有一件事。ViewModel依赖于模型。如果模型可以被外部服务/环境更改。是“全球国家”使事情变得复杂。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10437241

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档