如何监视自定义集合中集合对象的更改
本文关键字:集合 对象 自定义 何监视 监视 | 更新日期: 2023-09-27 18:21:05
我正在制作一个基于列表的自定义集合,其目的是可观察、防止重复、排序等。
我有一个这样的添加方法:
public class SortedObservableCollection<T> : List<T>, INotifyPropertyChanged, INotifyCollectionChanged
{
public void Add(T item)
{
base.Add(item);
base.Sort();
this.OnPropertyChanged("Count");
this.OnPropertyChanged("Item[]");
this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item);
}
}
但不知何故,当对象在集合中直接更改时,我需要自动进行调用,或者通知集合,以便它可以再次进行排序。
类似:
SortedObservableCollection<IRCUser> users = new SortedObservableCollection<IRCUser>();
users.Add(new IRCUser { Nick = "User1", Status = IRCUserStatus.Unknown });
users.Add(new IRCUser { Nick = "User2", Status = IRCUserStatus.Unknown });
users.Add(new IRCUser { Nick = "User3", Status = IRCUserStatus.Unknown });
users.Single(x => x.Nick == "User3").Nick = "User11";
User3位于集合的底部,请注意,我使用的是我自己的IComparable实现,它不仅仅是字母排序
我需要收集这个变化并通知我,这样我就可以做点什么了。
我知道我必须在对象上实现INotifyPropertyChanged,但我不确定的是集合将如何捕获它,我能看到的唯一方法是在add方法上是否执行:
item.PropertyChanged += (o,e) { ..check then... base.Sort(); };
但如果我有10000个用户,这是一条路吗?
项类必须实现INotifyPropertyChanged
那么您有两种选择:将列表(父级)保存在子类(项)中,并在项属性更改中调用某个方法
或者,当您将项目添加到列表中时,您会添加其NotifyPropertyChanged事件。我会走那条路。
列表:
public listclass()
{
this.ListChanged += new ListChangedEventHandler(listclass_ListChanged);
}
void listclass_ListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.ItemAdded)
{
item item = this[e.NewIndex];
item.PropertyChanged += new PropertyChangedEventHandler(Item_PropertyChanged);
}
}
void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "propertyname")
{
}
}
项实现INotifyPropertyChanged:
public item()
{
this.PropertyChanged += new PropertyChangedEventHandler(AnyPropertyChanged);
}
private void AnyPropertyChanged(object sender, PropertyChangedEventArgs e)
{
// example how to use
if (e.PropertyName == "anyproperyname")
{
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
private Boolean bTheProperty = true;
public Boolean TheProperty
{
get { return bTheProperty ; }
set
{
if (bTheProperty != value)
{
bTheProperty = value;
InvokePropertyChanged(new PropertyChangedEventArgs("TheProperty"));
}
}
}
在某些列表中,您必须将此属性设置为true,因此它会触发listchanged事件:
this.RaiseListChangedEvents = true;
如果你不想使用属性更改事件,你可以走这种肮脏的路:
private list oParent
public item(list parent)
{
this.oParent = parent;
}
private string sName;
public string Name
{
get { return sName; }
set
{
if (sName!= value)
{
sName= value;
if(this.parent != null)
{
this.parent.IsSorted = false;
}
}
}
}
然后可以在list类中使用计时器,检查isSorted是否为false,或者调用列表上的propertychanged。IsSorted属性。
正如我所认为的,解决方案似乎是向集合中的每个对象添加一个侦听器,并在移除该项时将其移除。我可以这样实现:
public class SortedObservableList<T> : List<T>, INotifyPropertyChanged, INotifyCollectionChanged where T : INotifyPropertyChanged, IComparable<T>
{
public void Add(T item)
{
base.Add(item);
base.Sort();
this.OnPropertyChanged("Count");
this.OnPropertyChanged("Item[]");
this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item);
item.PropertyChanged += InnerObjectChanged;
}
private void InnerObjectChanged(object sender, PropertyChangedEventArgs e)
{
base.Sort();
}
public bool Remove(T item)
{
item.PropertyChanged -= InnerObjectChanged;
bool result = base.Remove(item);
this.OnPropertyChanged("Count");
this.OnPropertyChanged("Item[]");
this.OnCollectionChanged(NotifyCollectionChangedAction.Remove, item);
return result;
}
protected virtual void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected virtual void OnCollectionChanged(NotifyCollectionChangedAction action, object item)
{
if (this.CollectionChanged != null)
{
this.CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public event NotifyCollectionChangedEventHandler CollectionChanged;
}
IRCUser
public class IRCUser : IComparable<IRCUser>, INotifyPropertyChanged
{
private string _nick;
public string Nick
{
get
{
return _nick;
}
set
{
if (value != _nick)
{
...
OnPropertyChanged();
}
}
}
public int CompareTo(IRCUser other)
{
...
}
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
我刚刚测试过这个,它似乎有效。