这似乎是一个基本问题,但我无法弄清楚最佳实施.如何管理两个视图模型及其相应模型之间的关系.
例如,如果您在PersonViewModel上更改了Occupation属性,那么该更改如何逐渐下降到PersonModel中的Occupation属性.
我现在唯一可以看到它的方法是在视图模型中公开展示模型,但我认为它击败了MVVM的目的 - 将模型与视图分离.
internal class PersonViewModel : INotifyPropertyChanged
{
private readonly PersonModel person;
private OccupationViewModel occupation;
public PersonViewModel(PersonModel person)
{
this.person = person;
}
public OccupationViewModel Occupation
{
get { return this.occupation; }
set
{
if (!this.occupation.Equals(value))
{
this.occupation = value;
this.person.Occupation = this.occupation.Occupation; // Doesn't seem right
this.OnPropertyChanged(new PropertyChangedEventArgs("Occupation"));
}
}
}
}
internal class OccupationViewModel : INotifyPropertyChanged
{
public OccupationViewModel(OccupationModel occupation)
{
this.Occupation = occupation;
}
public OccupationModel Occupation { get; set; } // Is this right?
}
internal class PersonModel
{
public OccupationModel Occupation { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
您的视图模型被解耦从视图模型.看起来您可能会混淆视图和视图模型的概念.
视图模型既是网关又是两者之间的守门人 - 它决定了从模型到视图以及从视图返回到模型的方式,以及以何种形式.
您可以在VM setter中设置model属性.您可以从视图中保存状态,并仅在用户单击"保存"时将这些更改传播到模型.你可以在其他地方坚持这种状态,这样有人可以在坚持到视图之前回来再努力.
视图模型可以非常熟悉模型,因此视图根本不需要知道它.
我不确定我是否关注在视图模型中公开展示模型.您还没有在示例代码中这样做.您已经公开了一个与您在模型中使用的类型相同的对象,但这就像int在模型和视图模型中使用age 一样- 您没有公开实际的模型对象; 您仍然可以控制是否以及何时在模型中设置视图模型中的值.
为了显示Model和ViewModel之间的可能关系,我首先通过更改Occupationinto 的类型来简化您的示例string.然后PersonModel,PersonViewModel可能看起来像这样:
public class PersonModel : INotifyPropertyChanged
{
private string occupation;
public string Occupation
{
get
{
return this.occupation;
}
set
{
if (this.occupation != value)
{
this.occupation = value;
this.OnPropertyChanged("Occupation");
}
}
}
}
public class PersonViewModel: INotifyPropertyChanged
{
private PersonModel model;
public string Occupation
{
get
{
return this.model.Occupation;
}
set
{
this.model.Occupation = value;
}
}
public PersonViewModel(PersonModel model)
{
this.model = model;
this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
}
private void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.OnPropertyChanged(e.PropertyName);
}
}
Run Code Online (Sandbox Code Playgroud)
与您的版本的重要区别在于PersonModel并且PersonViewModel 都实现了INotifyPropertyChanged.这很重要,因为否则PersonModel直接更改属性(即不经过PersonViewModel)将对View无效.还要注意PropertyChangedEvent模型如何通过管道传输到View.
现在假设Occupation不是一个string具有自己属性的类,例如:
public class OccupationModel : INotifyPropertyChanged
{
private double salary;
public double Salary
{
get
{
return this.salary;
}
set
{
if (this.salary != value)
{
this.salary = value;
this.OnPropertyChanged("Salary");
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在View和Model之间使用ViewModel可以灵活地将数据呈现给View.以下是两种选择:
选项1Occupation直接公开属性PersonViewModel.这是一个简单的解决方案,因为您不需要实现另一个ViewModel.
public class PersonViewModel: INotifyPropertyChanged
{
private PersonModel model;
public double OccupationSalary
{
get
{
return this.model.Occupation.Salary;
}
set
{
this.model.Occupation.Salary = value;
}
}
public PersonViewModel(PersonModel model)
{
this.model = model;
this.model.Occupation.PropertyChanged += new PropertyChangedEventHandler(occupation_PropertyChanged);
}
private void occupation_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.OnPropertyChanged("Occupation" + e.PropertyName);
}
}
Run Code Online (Sandbox Code Playgroud)
该OccupationSalary物业可直接进入Salary酒店Occupation.请注意现在需要处理的PropertyChanged事件Occupation,以及我们必须重命名该属性occupation_PropertyChanged.
选项2(推荐)Occupation通过a 公开属性OccupationViewModel.如果您需要实现特定于的任何业务逻辑,则应该执行此操作Occupation.举个例子,这可能是你打算做的:
public class PersonViewModel: INotifyPropertyChanged
{
private PersonModel model;
private OccupationViewModel occupationViewModel;
public OccupationViewModel OccupationViewModel
{
get
{
return this.occupationViewModel;
}
}
public PersonViewModel(PersonModel model)
{
this.model = model;
this.occupationViewModel = new OccupationViewModel(this.model.occupation);
}
}
public class OccupationViewModel : INotifyPropertyChanged
{
private OccupationModel model;
public double Salary
{
get
{
return this.model.Salary;
}
set
{
this.model.Salary = value;
}
}
public OccupationViewModel(OccupationModel model)
{
this.model = model;
this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
}
private void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.OnPropertyChanged(e.PropertyName);
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的OccupationViewModel那样,结构与PersonViewModel我在开头所展示的简化结构完全相同.你的版本最重要的区别OccupationViewModel是,它暴露了性质的OccupationModel,而不是OccupationModel自己.