Implementing IBindingListView... or not
Sometimes, it is very difficult to reuse existing code.
Today I wanted to code a class implementing the IBindingListView
. At first, I wanted to inherit the BindingList<T>
but then I discovered that some features were hidden, such as the AddIndex
. This method is not virtual and does not delegate to an AddIndexCore
method either.
So I decided to go deaper and starts coding using a Collection<T>
. But then, I realized that the indexer item is not virtual and does not delegate to an overridable method. As the IBindingListView
is supposed to be a view, I assume that the wrapped collection should not be affected by sorting and filtering. This also means that, once filtering or sorting are in effect, the view should become readonly, eventhough the wrapped collection does not have to be.
Also, BindingList<T>
is kind of the "reference" implementation of IBindingList
, because it is typed and in the framework. I might find existing code requiring BindingList<T>
, instead of IBindingList
, so inheriting from Collection<T>
might not be a good idea after all.
The IBindingList
, with the ListChanged
event, is intended to be an intermediate layer between business entities and user interface components. IBindingListView
, with only filtering and advanced sorting, could not have the same purpose. It clearly belongs in the realm of the user interface. The INotifyCollectionChanged
is better suited for code reuse, as it only focus on the observable aspect. The UI aspects is taken care of by the ICollectionView
. I just do not understand why the former is defined in the WindowsBase assembly, instead of, let say, System.Core. INotifyCollectionChanged
as nothing to do with UI.
The more thoughts I gave into it IBindingList
(and BindingList<T>
), the more it puzzles me. The AddIndex
/RemoveIndex
/Find
and ApplySort
/RemoveSort
are really abstract/general purpose methods intented to work with the user interface. And so are the IBindingListView
methods. The Filter method is very generic as it takes a string, so we have no idea on how we should interpret the filter. So it is strange that the IBindingList
does not declare a MoveItem
method, which is often needed in user interfaces.
[edit]The definition of the format for the filter can be found in the DataColumn.Expression help entry.[/edit]
The documentation states that the BindingSource implements IBindingListView
, which sounds great as it would be the perfect place to do so. It would have the reference implementation of the IBindingListView
. But, in fact, it only delegates the calls to the data source if it implements it (SupportsAdvanceSorting
& SupportsFiltering
returns true only when the List implements IBindingListView and supports them). "Implementation" is a little abusive in this case, don't you think?
So, I guess, IBindingListView
should be implemented as a decorator over a IList or IBindingList and, if we want to maximize its use, the BindingSource should be overriden as well, to instanciate this decorator when required.
The task list to do so is:
- Create a class that implement
IBindingListView
. This class does not have to be generic as it will mostly be used by the derivedBindingSource
. - Implement
IList
methods by delegation - Implement
IBindingList
methods by delegation whenever possible - Implement sorting and searching
- Create a
FilterExpressionParser
- Create a BindingViewSource that decorate a class with the
IBindingListView
- Implement MoveItem on the
BindingViewSource
Still, I'd like to point out that this task would be easier if we had a utility to, at least, parse the Filter expression.