在ItemsControl中,ViewModel内的INotifyPropertyChanged未触发

3

我正在使用 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");
    }
}

毋庸置疑,DataTemplate 中的绑定已设置为 Content="{Binding MyItem.SomeProperty}",它会显示正确的值。问题在于当我运行函数时,它没有更新。

附注:如果我在 MyItem 中实现了 INotifyPropertyChanged,它可以工作,但是我希望在 ViewModel 中实现。

1个回答

5
如果我在MyItem内部实现INotifyPropertyChanged,它是可以工作的,但我希望它在ViewModel上实现。
是的,因为这是它的设计。它应该知道它应该监听您的ViewModel属性更改事件吗?它不会绑定到它,而是绑定到模型,所以它会监听模型上的更改。
基本上你有两个选择:
  • Implement INotifyPropertyChanged on MyItem

  • Bind to the ViewModel

    Content="{Binding SomeProperty}"
    

    And add a wrapper property:

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

    You should prefer binding to the ViewModel if you want to follow MVVM practices.

附注:如果您像这样在 OnPropertyChanged 中添加 [CallerMemberName]
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
        }
    }

我明白了,所以我的错误是我应该在VM中添加一个包装器并绑定到它,而不是使用{Binding MyItem.SomeProperty} - Christopher Francisco
@Christopher 没错。问题在于当你绑定到 Foo.Bar.Baz 时,它将会监听 FooFoo.Bar 上的更改通知。在你的情况下,它会监听 MyItem 上的更改通知。 - Lucas Trzesniewski
哦,我明白了,非常感谢;我是.NET的新手(不仅是WPF),所以我一直很难理解它的内部工作原理(文章通常只说如何做,但不解释内部事项)。 - Christopher Francisco
不客气。如果你想更好地了解WPF的工作原理,我可以向你推荐这本书,它是WPF的作者之一写的:http://www.adamnathan.net/wpf/。 - Lucas Trzesniewski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接