前提
在默认的 MVVM 场景中,您的 ViewModel没有在每个属性上发出通知。
典型情况:您从数据库中获取一些Person,将它们显示在视图上,通过TextBoxes 和其他控件对其进行修改,然后单击“保存”将它们重新发送到数据库。您可以通过在每次调用数据库时在视图上设置DataContext 来做到这一点。此操作会引发控件和每个子控件的绑定属性的第一次更新,因此 ViewModel 绑定属性的所有 getter 都会被调用一次,并且 View 会使用 ViewModel 的值填充。当您在 View 上修改某些内容时,该绑定会将修改带到相应的 ViewModel 的属性(甚至是简单的普通 get-set 属性)。
在这种情况下,您可以使用以下内容:
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
//and so on...
}
仅当 View 必须侦听某些属性的更改时,您才需要为 ViewModel 的属性发出通知。例如,此功能:当且仅当Person 上的Name 不为空时,才会启用Button“保存”。在这里,显然Button 必须能够看到Name 属性何时发生变化,因此属性设置器必须引发PropertyChanged 事件。
一种可能的实现方式:
使用它作为 ViewModel 的基类:
protected abstract BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetAndNotifyIfChanged<T>(
ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
NotifyPropertyChanged(propertyName);
}
}
}
在派生类中,您可以像这样编写每个 get-set 属性:
class MyViewModel : BaseViewModel
{
public string MyProp
{
get { return _MyProp; }
set { SetAndNotifyIfChanged(ref _MyProp, value); }
}
private string _MyProp;
}
类型T和参数propertyName是自动推断出来的。
这是您可以编写的最短的代码,与普通的完整属性没有太大区别:
public string NormalProp
{
get { return _ NormalProp; }
set { _NormalProp = value; }
}
private string _MyProp;
如果您不想每次都编写所有这些代码,请使用code snippet。