Generics in ObjectListView
Posted on January 2, 2007
Note: You can download the complete implementation here.
My original implementation of ObjectListView wraps a list of arbitrary objects. It exposes these list items as type “object”, which means that you have to cast the returned items to your list item type. For example:
Listlist = new List (); ObjectListView view = new ObjectListView(list); list.Add(new SimpleClass(1, "aaa", DateTime.Now)); list.Add(new SimpleClass(5, "bbb", DateTime.Now)); view.FilterPredicate = delegate(object listItem) { return ((SimpleClass)listItem).IntegerValue == 5; }; Assert.AreEqual("bbb", ((SimpleClass)view[0]).StringValue);
Here we have to cast the result of view[0] back to SimpleClass.
Wouldn’t it be easier to use an ObjectListView that exposed the list items as their actual type?
ObjectListView<T>
You asked for it, and here it is. In version 1.0.0.7, I’ve added a version of ObjectListView that fully supports generics. The basic idea is that ObjectListView<T> takes an IList<T> as it’s constructor argument. The original ObjectListView takes a regular IList argument. Thus, we can re-write the above example this way:
Listlist = new List (); ObjectListView view = new ObjectListView (list); list.Add(new SimpleClass(1, "aaa", DateTime.Now)); list.Add(new SimpleClass(5, "bbb", DateTime.Now)); view.FilterPredicate = delegate(SimpleClass listItem) { return listItem.IntegerValue == 5; }; Assert.AreEqual("bbb", view[0].StringValue);
Because List<T> implements both IList and IList<T>, we can use the same underlying List<SimpleClass> for ObjectListView and ObjectListView<SimpleClass>.
Note that in addition to the indexer returning SimpleClass (e.g. view[0]), the FilterPredicate property is now a delegate type that takes an instance of the list item type (T) as a parameter, instead of type object.
Differences between ObjectListView and ObjectListView<T>
With ObjectListView<T>, the list item type is expressed right in the declaration of the view: ObjectListView<SimpleClass> is a view of SimpleClass list items. This means that the ItemType property is not needed in ObjectListView<T>. It also obviates the need for internal checks to see that the list item type is specified and that the list items are homogeneous.
Interestingly, IList<T> does not derive from IList. This has important ramifications for ObjectListView. It’s primary role is to implement IBindingListView, which derives from IBindingList, IList, ICollection, and IEnumerable. So we’re not off the hook for supporting those interfaces. Assuming that the consumer of ObjectListView<T> will be most interested in using the generic interfaces, I’ve chosen to make the weakly-typed interfaces explicit implementations. This means that both IList and IList<T> are supported, but the methods of IList<T> are the public ones. If you want to access an IList method, you just need to cast ObjectListView<T> to an IList first.
ICollection<T> (the base of IList<T>) doesn’t offer the IsSynchronized or SyncRoot members of ICollection. The consequence of this is that ObjectListView<T> need not worry about thread synchronization with the underlying list; there isn’t anything to synchronize with. Similarly, IList<T> does not provide the IsFixedSize property of IList, which eliminates more housekeeping code.
Both the event arguments of the AddingNew event and the ObjectView wrapper returned by AddNew() are strongly typed now.
As noted in the code example above, the ListItemFilter delegate type used by the FilterPredicate property is also strongly typed.
Updated Demo
I changed the Master/Details demo included in the download to use the generic version of ObjectListView. I also added menu options to demonstrate filtering the list displayed in the grid.
Of course, the original “non-generic” version of ObjectListView is still included in the download, so if you prefer that, by all means use it!
Happy New Year!
Got something to say?