1

我正在制作一个基于列表的自定义集合,其目的是可观察、防止重复、排序等。

我有一个像这样的添加方法:

    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(); };

但是如果我有 10,000 个用户,这是要走的路吗?

4

2 回答 2

0

项目类必须实现,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; 
       }
     }           
   }
}

然后您可以在列表类中使用计时器并检查 isSorted 是否为假,或者调用 list.IsSorted 属性上的 propertychanged。

于 2013-07-04T12:25:30.290 回答
0

正如我认为的那样,解决方案似乎是为集合中的每个对象添加一个侦听器,并在删除项目时将其删除。我可以这样实现:

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;
}

IRC 用户

    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;
    }

我刚刚测试过这个,它似乎工作。

于 2013-07-04T13:09:19.627 回答