Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/silverlight/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MVVM:绑定到模型,同时保持模型与服务器版本同步_C#_Silverlight_Mvvm_Domain Driven Design_Prism - Fatal编程技术网

C# MVVM:绑定到模型,同时保持模型与服务器版本同步

C# MVVM:绑定到模型,同时保持模型与服务器版本同步,c#,silverlight,mvvm,domain-driven-design,prism,C#,Silverlight,Mvvm,Domain Driven Design,Prism,我已经花了相当长的时间试图为下面的挑战找到一个优雅的解决方案。我一直找不到一个解决方案,这不仅仅是对问题的一种破解 我有一个视图、视图模型和模型的简单设置。为了便于解释,我将把它保持得非常简单 Model有一个名为Title的字符串类型属性 模型是视图的数据上下文 视图有一个文本块,该块数据绑定到模型上的标题 ViewModel有一个名为Save()的方法,该方法将Model保存到Server 服务器可以推送对型号所做的更改 到目前为止还不错。现在我需要做两个调整,以使模型与服务器保持同步。

我已经花了相当长的时间试图为下面的挑战找到一个优雅的解决方案。我一直找不到一个解决方案,这不仅仅是对问题的一种破解

我有一个视图、视图模型和模型的简单设置。为了便于解释,我将把它保持得非常简单

  • Model
    有一个名为
    Title
    的字符串类型属性
  • 模型
    视图
    的数据上下文
  • 视图
    有一个
    文本块
    ,该块数据绑定到模型上的
    标题
  • ViewModel
    有一个名为
    Save()
    的方法,该方法将
    Model
    保存到
    Server
  • 服务器可以推送对
    型号所做的更改
到目前为止还不错。现在我需要做两个调整,以使模型与
服务器保持同步。服务器的类型并不重要。只需知道我需要调用
Save()
,以便将模型推送到
服务器。

调整1:

  • Model.Title
    属性需要调用
    RaisePropertyChanged()
    ,以便将
    服务器对
    模型所做的更改转换到
    视图中。这非常有效,因为
    模型
    视图的数据上下文
还不错

调整2:

  • 下一步是调用
    Save()。这就是我被卡住的地方。我可以处理
    ViewModel
    上的
    Model.PropertyChanged
    事件,该事件在模型发生更改时调用Save(),但这会使它回显服务器所做的更改

我正在寻找一个优雅且合乎逻辑的解决方案,如果有意义,我愿意更改我的体系结构。

如果您唯一的问题是服务器的更改会立即重新保存,为什么不执行以下操作:

//WARNING: typed in SO window
public class ViewModel
{
    private string _title;
    public string Title
    {
        get { return _title; }
        set
        {
            if (value != _title) 
            {
                _title = value;
                this.OnPropertyChanged("Title");
                this.BeginSaveToServer();
            }
        }
    }

    public void UpdateTitleFromServer(string newTitle)
    {
        _title = newTitle;
        this.OnPropertyChanged("Title"); //alert the view of the change
    }
}

此代码在不经过属性设置程序的情况下,从服务器手动提醒视图属性更改,因此也不调用“保存到服务器”代码。

出现此问题的原因是您的模型不知道它是否脏

string Title {
  set {
    this._title = value;
    this._isDirty = true; // ??!!
  }
}}
解决方案是通过单独的方法复制服务器更改:

public void CopyFromServer(Model serverCopy)
{
  this._title = serverCopy.Title;
}

仅当模型实现INotifyPropertyChanged接口时,将模型直接绑定到视图才有效。(例如,实体框架生成的模型)

模型实现INotifyPropertyChanged 你可以这样做

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
}
视模型为DTO 若模型实现了INotifyPropertyChanged(具体取决于),那个么在大多数情况下,您可以将其用作DataContext。但在DDD中,大多数MVVM模型将被视为实体对象,而不是实际域的模型

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

//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依赖于模型。如果模型可以由外部服务/环境更改。让事情变得复杂的是“全局状态”。

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

安装程序
  • 视图始终绑定到视图模型。我知道这是很多样板,但是直接绑定到模型在任何情况下都是不可接受的,除非是最简单的场景;这也不符合MVVM的精神

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

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

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

    这使得ViewModels可以在其他ViewModels已推送到数据存储的“他们的”模型发生更改时得到通知,并做出相应的反应。通过适当的抽象,数据存储也可以是任何东西(例如,特定应用程序中的WCF服务)

  • 工作流程
  • 将创建ViewModel并指定模型的所有权。它会立即克隆模型并将此克隆公开给视图。由于依赖于数据服务,它告诉DS它想订阅此特定模型的更新通知。ViewModel不知道标识其模型的是什么(“主键”),但它不需要知道,因为这是DS的责任

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

  • DS保留更改,并另外引发一个事件,通知所有其他感兴趣的VM已对模型X进行了更改;新版本的