nds*_*dsc 27 c# silverlight domain-driven-design prism mvvm
说我有一个Person班级,一个PersonViewModel和一个PersonView.
将属性更新PersonView到Person模型很简单.PersonViewModel包含一个Person对象,并具有PersonView绑定到的公共属性,以便更新Person模型.
然而.
想象一下,Person模型可以更新Service.现在需要将属性更改传达给PersonViewModel然后再传递给PersonView.
我就是这样解决的:
对于Person模型中的每个属性,我将引发PropertyChanged事件.PersonViewModel订阅了PropertyChanged事件Person.PersonViewModel然后会引发另一个PropertyChanged以更新PersonView.
这对我来说似乎是最明显的方式,但我有点想把这个问题抛到那里,希望有人能给我一个更好的方法.这真的很简单,还是有更好的方法将模型标记为已修改并更新ViewModel上的相应属性?
该PersonView的DataContext的是PersonViewModel.Person从JSON填充并在其生命周期内多次更新.
随意为我的特定情况建议架构更改.
我将aqwert标记为我问题的答案,因为它为我提供了我已经提出的解决方案的替代方案.
PVi*_*itt 28
当视图直接绑定到模型时,您正在混合UI代码和数据代码.MVVM的目的是分离这两个代码域.这就是ViewModel的用途.
视图模型必须具有视图可以绑定的自己的属性.一个例子:
class PersonViewModel
{
private Person OriginalModel { get; set; }
public ValueViewModel<string> Name { get; set; }
public ValueViewModel<int> Postcode { get; set; }
protected void ReadFromModel(Person person)
{
OriginalModel = person;
Name.Value = OriginalModel.Name;
Postcode.Value = OriginalModel.Postcode;
}
protected Person WriteToModel()
{
OriginalModel.Name = Name.Value; //...
return OriginalModel;
}
}
Run Code Online (Sandbox Code Playgroud)
使用这样的ViewModel设计实际上将数据对象与用户界面代码分开.当Person更改时,UI不需要适合,因为ViewModel将它们分开.
现在回答你的问题.正如您在上面的示例中所看到的,我使用了泛型ValueViewModel<T>.这个类实现INotifyPropertyChanged(以及其他一些东西).但是当你收到一个新的Person时,你只需要调用Person你的ViewModel来更新UI,因为View绑定的ValueViewModels会在它们的值发生变化时通知UI.
这里是一个极其简化的内部结构示例ReadFromModel(newPerson):
class ValueViewModel<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value;}
set
{
_value = value;
RaisePropertyChanged("Value");
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我们在MVVM库中使用的方法.它的优势在于它迫使开发人员明确地将其代码与设计人员的关注点分开.作为副作用,它在所有视图和ViewModel中生成标准化的代码布局,从而提高代码质量.
如果视图直接绑定到Model,那么只要服务使用相同的实例,对模型属性的任何更改都将传播到视图.
但是,如果要在服务中重新创建新模型,则会为viewmodel指定新模型.我希望将模型视为视图模型上的属性,因此当您设置该属性时,应该提醒所有绑定更改.
//in the ViewModel
public Person Model
{
get { return _person; }
set { _person = value;
RaisePropertyChanged("Model"); //<- this should tell the view to update
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
既然你声明有特定的ViewModel逻辑,那么你可以在中定制那些属性ViewModel
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Prop1") RaisePropertyChanged("SpecicalProperty");
...
}
public string SpecicalProperty
{
get
{
reutrn Model.Prop1 + " some additional logic for the view";
}
}
Run Code Online (Sandbox Code Playgroud)
在XAML
<TextBlock Text="{Binding Model.PropertyDirect}" />
<TextBlock Text="{Binding SpecicalProperty}" />
Run Code Online (Sandbox Code Playgroud)
这样,只有Model和ViewModel属性绑定到视图而不重复数据.
您可以更好地创建帮助程序,以将属性更改从模型链接到视图模型或使用映射字典
_mapping.Add("Prop1", new string[] { "SpecicalProperty", "SpecicalProperty2" });
Run Code Online (Sandbox Code Playgroud)
然后通过获取属性列表找到要更新的属性
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
string[] props;
if(_mapping.TryGetValue(e.PropertyName, out props))
{
foreach(var prop in props)
RaisePropertyChanged(prop);
}
}
Run Code Online (Sandbox Code Playgroud)