我花了相当长的时间试图为下面的挑战找到一个优雅的解决方案。我一直找不到解决问题的办法。
我有一个简单的设置视图,ViewModel和一个模型。为了解释起见,我会把它写得很简单。
Model有一个名为String类型的Title的属性。Model是View的DataContext。View有一个TextBlock,该数据库可以在模型上指向Title。ViewModel有一个名为Save()的方法,它可以将Model保存到一个Server,可以将更改推到Model上。
到目前一切尚好。现在,我需要做两个调整,以使模型与Server保持同步。服务器的类型并不重要。只需知道我需要调用Save()才能将模型推送到Server.
调整1:
Model.Title属性需要调用RaisePropertyChanged(),以便将Server对Model所做的更改转换为View。这很好,因为View的Model是DataContext
不算太坏。
调整2:
Save()以保存从View到Server上的Model所做的更改。这就是我被困的地方。当模型被更改时,我可以在ViewModel上处理调用Save()的ViewModel事件,但这使它与Server.所做的更改相呼应。
我正在寻找一个优雅而合乎逻辑的解决方案,如果有意义的话,我愿意改变我的架构。
发布于 2012-05-04 08:34:03
过去,我曾编写过一个应用程序,它支持多个位置的数据对象“实时”编辑:应用程序的许多实例可以同时编辑同一个对象,当有人向服务器推送更改时,其他所有人都会得到通知,并且(在最简单的情况下)立即看到这些更改。下面简要介绍一下它是如何设计的。
设置
的精神。
要做到这一点,ViewModels可能希望克隆它们包装的模型,这样它们就可以为应用程序的其余部分提供事务语义,就像它们提供给服务器一样(也就是说,您可以选择何时将更改推送到应用程序的其余部分,如果每个人都直接绑定到同一个Model实例,则不能这样做)。隔离这样的更改需要做更多的工作,但它也提供了强大的可能性(例如,取消更改是微不足道的:只是不要推它们)。
这允许ViewModels被告知对“他们的”模型的更改,而其他ViewModels已经将这些更改推送到数据存储中,并做出了适当的反应。有了适当的抽象,数据存储也可以是任何东西(例如,特定application).中的WCF服务)。
工作流程
的责任。
当用户完成编辑时,
。
备注
possible).
INotifyPropertyChanged只供视图使用;如果ViewModel想知道模型是否“脏”,它总是可以将克隆与原始版本进行比较(如果它一直在附近,我建议如果 ViewModel原子地将更改推送到服务器,这很好,因为它确保数据存储始终处于一致状态。这是一种设计选择,如果您想以不同的方式处理事情,另一种设计将是更多的appropriate.this作为参数传递给“推送更改”调用。即使没有,如果ViewModel看到模型的“当前”版本与它自己的克隆版本相同,它可以选择什么也不做。具有足够抽象性的希望这有帮助;如果需要的话,我可以提供更多的澄清。
发布于 2012-05-04 08:52:28
我建议在MVVM组合中添加控制器(MVCVM?)以简化更新模式。
控制器侦听较高级别的更改,并在模型和ViewModel之间传播更改。
保持事物清洁的基本规则是:
是有意义的。
正如在另一个答案中提到的,您的DataContext应该是VM (或它的属性),而不是模型。针对DataModel,很难将关注点分离开来(例如,用于测试驱动的开发)。
大多数其他解决方案都将逻辑放在ViewModels中,这是“不正确的”,但我看到控制器的好处一直被忽视。该死的MVVM首字母缩写!:)
发布于 2012-05-04 06:49:09
只有当模型实现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
}ViewModel作为DTO
如果模型实现了INotifyPropertyChanged(这取决于),那么在大多数情况下,您可以使用它作为DataContext。但在DDD中,大多数MVVM模型被认为是EntityObject模型,而不是一个真正的域模型。
更有效的方法是使用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依赖于模型。如果模型可以被外部服务/环境更改。是“全球国家”使事情变得复杂。
https://stackoverflow.com/questions/10437241
复制相似问题