在WPF中使用带有ObservableCollection的HashSets

Ale*_*all 7 c# wpf observablecollection hashset

我正在使用ListBox来维护WPF应用程序中的项目列表.ListBox数据源是一个包含在ObservableCollection中的HashSet.即,我有以下代码:

this.shackSet = new ObservableCollection<Shack>(new HashSet<Shack>());
this.shackListing.ItemsSource = this.shackSet;
Run Code Online (Sandbox Code Playgroud)

...其中shackListing是一个ListBox控件,另一个是ICollection中的shackSet.但是,每当我在添加第一个项目后向shackSet添加任何内容时,我会在ListBox中看到多个项目.即,就像新添加的项目被添加到列表中一样,无论它们是否已添加到集合中.当我看到ICollection的签名#Add:

void Add(T obj);
Run Code Online (Sandbox Code Playgroud)

...和HashSet #Add:

bool Add(T obj); 
Run Code Online (Sandbox Code Playgroud)

......这使我相信有一个影响包裹HashSets其中新添加的项目被添加到列表框,无论是因为的ObservableCollection没有告诉该对象是否实际添加到收藏垫层的方式中的错误,因为ICollection的#返回类型添加无效.其他人可以证实这一点吗?

bit*_*onk 9

当您使用另一个集合创建一个新的ObservableCollection时,您没有包装该集合,而是创建一个新的集合,其中传递的集合的所有项都被复制到ObservableCollection.如果您想将ObservableCollection用于DataBinding的唯一目的,那么您可以将其绑定到WPF中的任何IEnumerable.这不幸地有一个缺点,即WPF不会总是正确地拾取绑定集合的更改.如果这是一个问题,您可能需要创建自己的obeservable hashset:

public class ObservableHashSet<T> : ObservableCollection<T>  
{ 
    protected override void InsertItem(int index, T item) 
    { 
        if (Contains(item)) 
        {
            throw new ItemExistsException(item); 
        }
        base.InsertItem(index, item); 
    } 

    protected override void SetItem(int index, T item) 
    { 
        int i = IndexOf(item); 
        if (i >= 0 && i != index)
        {
             throw new ItemExistsException(item); 
        }       
        base.SetItem(index, item); 
    } 
}
Run Code Online (Sandbox Code Playgroud)

编辑:AS已经指出,你不能从HashSet继承来实现INotifyCollectionChanged.但是,如果你看一下HashSet类的代码(使用Reflector),那么很难自己模仿这个功能.

  • 我想指出,虽然这个类可能有一个哈希集的接口,但它确实没有它的性能.调用哈希集,因为它使用哈希码来定位(理想情况下)恒定时间内的项目.您的实现需要线性时间.因此,我只会在非性能关键的情况下使用它.另外,我可能只称它为"ObservableSet"(没有"Hash")部分. (12认同)
  • 给Thomas说的是+1,除了你不能继承`HashSet`并实现`INotifyCollectionChanged`,因为`HashSet`方法不是虚拟的,不能被覆盖.你必须实现`ICollection`,你的实现必须_wrap_`HashSet`并在所有变异方法上发出通知. (2认同)