当我绑定到IEnumerable时,WPF如何知道使用INotifyPropertyChanged

本文关键字:何知道 INotifyPropertyChanged WPF 绑定 IEnumerable | 更新日期: 2023-09-27 18:05:01

在视图模型(下面的SomeViewModel)中,Data属性返回IEnumerable<IData>,其中两个接口都没有实现INotifyPropertyChanged

然而,底层数据字段是ObservableCollection<ObservableData>,两个类都实现了INotifyPropertyChanged

最后,在XAML中,Data被绑定到DataGrid。

我认为这个绑定可能会引入KB938416中描述的绑定内存泄漏,但令我惊讶的是它没有。

当方法ChangeData被调用时,我可以看到DataGrid被更新,OnPropertyChanged被调用处理程序。

我的问题是:当绑定数据返回IEnumerable<IData>时,WPF如何知道使用INotifyPropertyChanged(两者都不实现INotifyPropertyChanged)?

public interface IData
{
    string Name { get; }
}    
// In addition to IData, implements INotifyPropertyChanged
public class ObservableData : IData, INotifyPropertyChanged
{
    private string _name;    
    public string Name
    {
        get { return this._name; }    
        set
        {
            if (_name == value) { return; }
            _name = value;
            OnPropertyChanged("Name");                
        }
    }
    // 'OnPropertyChanged' omitted for brevity
}
// here is some ViewModel
public class SomeViewModel
{
    private ObservableCollection<ObservableData> _data = new ObservableCollection<ObservableData>();
    // In XAML, a DataGrid's ItemsSource is bound to this.
    public IEnumerable<IData> Data { get { return _data; } }
    public void ChangeData()
    {
        // test OC's notification
        _data.Add(new ObservableData {Name = "new" });
        // test ObservableData's notification
        _data[0].Name += " and changed";
    }
}

当我绑定到IEnumerable时,WPF如何知道使用INotifyPropertyChanged

在您的案例中,Data属性不需要INotifyPropertyChanged

Data是ObservableCollection类型,它内部实现了INotifyCollectionChanged。

因此,无论何时添加或删除项,视图都会收到通知。

即使您的Data属性以IEnumerable<IData>的类型返回,对象本身仍然是ObservableCollection<ObservableData>。WPF可以只使用isas操作符来测试任何特定对象是否实现了INotifyPropertyChanged,而不管提供的句柄是什么。

IEnumerable<IData> test = Data;
if (test is INotifyPropertyChanged) { 
    //This if block enters because test is really ObservableCollection<ObservableData>
    INotifyPropertyChanged test2 = (INotifyPropertyChanged)test;
}