INotifyPropertyChanged 不会在 ItemsControl 内的 ViewModel 上触发

Chr*_*sco 3 c# wpf mvvm

我正在使用ObservableCollection<MyItemViewModel> myItemVMList作为ItemsSouce. 我能够Command完美绑定,但INotifyPropertyChanged无法正常工作。这是我的代码:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Luc*_*ski 5

如果我在INotifyPropertyChanged内部实现MyItem它可以工作,但我希望它在ViewModel

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

您基本上有两种选择:

  • 实施INotifyPropertyChangedMyItem

  • 绑定到 ViewModel

    Content="{Binding SomeProperty}"
    
    Run Code Online (Sandbox Code Playgroud)

    并添加一个包装器属性:

    public string SomeProperty
    {
        get { return MyItem.SomeProperty; }
        set
        {
            MyItem.SomeProperty = value;
            OnPropertyChanged("SomeProperty");
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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


附注:如果您添加[CallerMemberName]OnPropertyChanged这样的:

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

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

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