BindingList<T> 不会在编辑时触发 ListChanged

BindingList<T> does not fire ListChanged on edits

我的 objective 是制作一个列表,当元素发生变化时会触发一个事件。想法是创建一个 BindingList 的实体,实现 INotifyChanged 将该事件转发给 ViewModel。

我目前拥有的:

public class ViewModel
{
    public TagPresenter Tags {get;}
    public ViewModel()
    {
        Tags = new TagPresenter();

        Tags.TagCollection.ListChanged += (object o, ListChangedEventargs e) => { DataAccessor.UpdateTag(o[e.NewIndex]); };

        foreach(var tag in DataAccessor.GetTags())
            Tags.TagCollection.Add(new TagEntity(tag, Tags.TagCollection));
    }
}

public class TagPresenter
{
    public BindingList<object> TagCollection {get;}

    public TagPresenter()
    {
        TagCollection = new BindingList<object>();
    }
}

public class TagEntity : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged {get;}
    public Command ChangeState {get;}

    public TagEntity(string tag, BindingList<object> parent)
    {
        ChangeState = new Command(new Action(() => {
            NotifyPropertyChanged("Property");
        }));
    }

    public void NotifyPropertyChanged(string _property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(_property));
    }
}

在此代码中,ListChanged 事件在 foreach 循环中将新实体添加到列表中时触发,但在我触发 BindingList 中实体的 PropertyChanged 时不会触发(NotifyPropertyChanged 方法中的断点停止,但 ListChanged 事件未触发)

好的,明白了,问题是由于 TagEntity 与 BindingList 中的对象之间的 boxing\unboxing。一旦我添加了实现 INotifyChanged 的​​抽象 class TagBase,并将集合切换到 BindingList,它就会按预期工作:

public class ViewModel
{
    public TagPresenter Tags {get;}
    public ViewModel()
    {
        Tags = new TagPresenter();

        Tags.TagCollection.ListChanged += (object o, ListChangedEventargs e) => { DataAccessor.UpdateTag(o[e.NewIndex]); };

        foreach(var tag in DataAccessor.GetTags())
            Tags.TagCollection.Add(new TagEntity(tag, Tags.TagCollection));
    }
}

public class TagPresenter
{
    public BindingList<TagBase> TagCollection {get;}

    public TagPresenter()
    {
        TagCollection = new BindingList<TagBase>();
    }
}

public abstract class TagBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged {get;}

    public void NotifyPropertyChanged(string _property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(_property));
    }
}

public class TagEntity : TagBase
{
    public Command ChangeState {get;}

    public TagEntity(string tag, BindingList<TagBase> parent)
    {
        ChangeState = new Command(new Action(() => {
            NotifyPropertyChanged("Property");
        }));
    }

}