INotifyPropertyChanged 未在 ItemsControl 内的 ViewModel 上触发

INotifyPropertyChanged not firing on ViewModel inside ItemsControl

我正在使用 ObservableCollection<MyItemViewModel> myItemVMList 作为 ItemsSouce。我可以完美地绑定 CommandINotifyPropertyChanged 不工作。这是我的代码:

public class MyItemViewModel: INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name) {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    public MyItem MyItem { set; get; }

    private RelayCommand _ChangeMyItemPropertyValue;
    public ICommand ChangeMyItemPropertyValueCommand {
        get {
            if (_ChangeMyItemPropertyValue == null) _ChangeMyItemPropertyValue = new RelayCommand(o => ChangeMyItemPropertyValue());
            return _ChangeMyItemPropertyValue;
        }
    }
    private ChangeMyItemPropertyValue() {
        MyItem.SomeProperty = someDifferentValue;

        // NEITHER OF THESE CALLS WORK
        OnPropertyChanged("MyItem.SomeProperty");
        OnPropertyChagned("SomeProperty");
    }
}

不用说,DataTemplate 中的绑定设置为 Content="{Binding MyItem.SomeProperty}",它显示了正确的值。问题是当我 运行 函数时它没有更新。

旁注: 如果我在 MyItem 中实现 INotifyPropertyChanged 它可以工作,但我希望它在 ViewModel.

If I implement the INotifyPropertyChanged inside MyItem it works, but I want it on the ViewModel

是的,因为它就是这样设计的。它应该如何知道它应该监听您的 ViewModel 的 属性 changed 事件?它不绑定到它,它绑定到模型,所以它会监听模型上的变化。

基本上你有两个选择:

  • MyItem

  • 上实施 INotifyPropertyChanged
  • 绑定到 ViewModel

    Content="{Binding SomeProperty}"
    

    并添加包装器 属性:

    public string SomeProperty
    {
        get { return MyItem.SomeProperty; }
        set
        {
            MyItem.SomeProperty = value;
            OnPropertyChanged("SomeProperty");
        }
    }
    

    如果您想遵循 MVVM 实践,您应该更喜欢绑定到 ViewModel。


旁注:如果像这样将 [CallerMemberName] 添加到 OnPropertyChanged

protected void OnPropertyChanged([CallerMemberName] string name = null) {
    var handler = PropertyChanged;
    if (handler != null)
        handler(this, new PropertyChangedEventArgs(name));
}

您将能够完全跳过 属性 名称:

    public string SomeProperty
    {
        get { return MyItem.SomeProperty; }
        set
        {
            MyItem.SomeProperty = value;
            OnPropertyChanged(); // <-- no need for property name anymore
        }
    }