C#,WPF,MVVM和INotifyPropertyChanged

Ala*_*lan 9 c# wpf mvvm inotifypropertychanged

我感到困惑; 我以为我理解了INotifyPropertyChanged.

我有一个小的WPF应用程序,前端是MainWindow类,中间有一个视图模型,后面有一个模型.

我的模型是模拟器类.

SimulatorViewModel几乎是透明的,只是MainWindow和Simulator之间的接口属性.

Simulator实现了INotifyPropertyChanged,Simulator中的每个属性setter都调用了RaisePropertyChanged方法:

private string serialNumber;
public string SerialNumber
{
    get { return serialNumber; }
    set
    {
        serialNumber = value;
        RaisePropertyChanged("SerialNumber");
    }
}

public event PropertyChangedEventHandler PropertyChanged;

public void RaisePropertyChanged(string propName)  
{  
    if (this.PropertyChanged != null)  
    {  
        this.PropertyChanged(this, new PropertyChangedEventArgs(propName));  
    }  
}    
Run Code Online (Sandbox Code Playgroud)

在xaml中,我有一个带有这样绑定的TextBox:

Text="{Binding Path=SerialNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Run Code Online (Sandbox Code Playgroud)

并且DataContext是SimulatorViewModel(但是请参阅我关于将DataContext更改为模型的注释)

ViewModel只传递属性:

public string SerialNumber  
{  
    get { return Simulator.SerialNumber; }  
    set { Simulator.SerialNumber = value; }  
}  
Run Code Online (Sandbox Code Playgroud)

Simulator中属性SerialNumber的编程更新不会传播到UI,但奇怪的是,在Simulator构造函数中设置的初始值正在到达那里.

如果我在模拟器中断开SerialNumber setter并进入RaisePropertyChanged,我发现PropertyChanged为null,因此事件不会向上传播到GUI.

这引出了几个问题:

  1. 究竟应该挂进PropertyChanged事件?我希望比"WPF"更具体.该事件与xaml中的Binding语句之间的联系是什么?

  2. 为什么初始属性值在启动时会到达UI,但后来却没有?

  3. 我是否有权使用模拟器(模型)实现INotifyPropertyChanged,或者它应该是ViewModel吗?如果ViewModel这样做,那么模型中的程序化更改不会触发PropertyChanged,所以我不清楚正确的模式.我意识到我的ViewModel实际上是多余的,但这是由于项目的简单性; 更复杂的一个会使ViewModel概念更加努力.我的理解是ViewModel是我的单元测试接口的地方.

Sno*_*ear 7

  1. 问题在于你正在提升PropertyChanged模型,但你的视图与ViewModel绑定.因此,您的View仅订阅ViewModel事件(而非Model) - 这就是文本框未更新的原因 - 因为它永远不会收到PropertyChanged事件.一种可能的解决方案是在ViewModel中侦听Model PropertyChanged事件并相应地在ViewModel上引发相同的事件.

  2. 正在传播初始值,因为ViewModel中的setter/getter是正确的,问题出在事件中.

  3. 是的,你是对的(参见我的#1),你应该PropertyChanged在你的ViewModel上加注,因为View绑定了它.模型更改后,这些事件不会自动触发,因此您应该Model.PropertyChanged在ViewModel中监听.

理解这个想法最简单的脏修复:

SimulatorViewModel(Simulator model)
{
    // this will re-raise Model's events on ViewModel
    // VM should implement INotifyPropertyChanged
    // method OnPropertyChanged should raise INPC for a given property
    model.PropertyChanged += (sender, args) => this.OnPropertyChanged(args.PropertyName);
}
Run Code Online (Sandbox Code Playgroud)