Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing INotifyCollectionChanged on a collection without indexes

Tags:

c#

wpf

I am just now getting my toes wet in WPF after several years of working in ASP.Net exclusively. The problem I am currently struggling with is that I have a custom collection class which I need to bind to a listbox. Everything seems to be working except for removing an item from the collection. When I try to I get the error: “Collection Remove event must specify item position.” The catch is that this collection does not use indexes so I am not seeing a way to specify the position and so far Google has failed to show me a workable solution…

The class is defined to implement ICollection<> and INotifyCollectionChanged. My internal items container is a Dictionary which uses the item’s Name(string) value for a key. Aside from the methods defined by these two interfaces, this collection has an indexer that allows items to be accessed by Name, and overrides for the Contains and Remove methods so that they can also be called with the item Name. This is working for Adds and Edits but throws the above exception when I try to remove.

Here is an excerpt of the relevant code:

class Foo
{
    public string Name
    {
        get;
        set;
    }
}
class FooCollection : ICollection<Foo>, INotifyCollectionChanged
{
    Dictionary<string, Foo> Items;

    public FooCollection()
    {
        Items = new Dictionary<string, Foo>();
    }

    #region ICollection<Foo> Members

    //***REMOVED FOR BREVITY***

    public bool Remove(Foo item)
    {
        return this.Remove(item.Name);
    }
    public bool Remove(string name)
    {
        bool Value = this.Contains(name);
        if (Value)
        {
            NotifyCollectionChangedEventArgs E = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, Items[name]);
            Value = Items.Remove(name);
            if (Value)
            {
                RaiseCollectionChanged(E);
            }
        }
        return Value;
    }
    #endregion

    #region INotifyCollectionChanged Members
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, e);
        }
    }
    #endregion
}
like image 473
Rozwel Avatar asked Jun 06 '11 16:06

Rozwel


1 Answers

Your custom collection seems like a re-invention of KeyedCollection<TKey,TItem>, which internally uses a dictionary, and has indexes. The indexer for int indexes can get hidden if TKey is int or int-based enum, but this can be fixed.

As for making KeyedCollection work with WPF, I found this article, in which he basically makes an ObservableKeyedCollection<TKey,TItem> by implementing INotifyCollectionChanged and overriding SetItem(), InsertItem(), ClearItems(), and RemoveItem(), along with adding AddRange() and passing a Func<TItem,TKey> to the constructor for getting the TKey from a TItem.

like image 125
Joel B Fant Avatar answered Sep 24 '22 13:09

Joel B Fant