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");
}));
}
}
我的 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");
}));
}
}