.NET Forum / Windows Forms / WinForm Controls / January 2006
Filtering a BindingList<T> is not possible?
|
|
Thread rating:  |
Benton - 15 Jan 2006 10:28 GMT Hi there,
I've googled for hours in search for a filtering mechanism for a BidingList<T> inherited class. I found several examples for sorting and searching but none for filtering. I mean filtering within the class itself, without using BindingSource.
Does anyone knows why? Any pointers?
Best Regards,
-Benton
Benton - 15 Jan 2006 17:15 GMT > I've googled for hours in search for a filtering mechanism for a > BidingList<T> inherited class. I found several examples for sorting and > searching but none for filtering. I mean filtering within the class > itself, without using BindingSource. Duh. Last time I post at 4:00 am on a Sunday. :-)
It turns out the problems is this: I have the BindingList binded to a DataGridView. On the click of a button, I filter the BindingList, setting some items as "invisible". Although "foreach" honors the filter, the DataGridView does not. I think it's because the grid it is not using my custom "new" enumerator (with filtering support) and it's using the base class enumerator. Yes, I am raising ListChanged event with Reset parameter.
Time to forget the BindingList class and go back to my own IBindingList implementation. Arrrgggh!
Regards,
-Benton
Bart Mermuys - 15 Jan 2006 17:56 GMT Hi,
>> I've googled for hours in search for a filtering mechanism for a >> BidingList<T> inherited class. I found several examples for sorting and [quoted text clipped - 10 lines] > class enumerator. Yes, I am raising ListChanged event with Reset > parameter. No, afaik it doesn't use the enumerator, it uses the IList interface ( Count and Item (indexer in c#) ), it needs random access.
HTH, Greetings
> Time to forget the BindingList class and go back to my own IBindingList > implementation. Arrrgggh! > > Regards, > > -Benton Benton - 16 Jan 2006 17:46 GMT >> It turns out the problems is this: I have the BindingList binded to a >> DataGridView. On the click of a button, I filter the BindingList, setting [quoted text clipped - 3 lines] >> class enumerator. Yes, I am raising ListChanged event with Reset >> parameter.
> No, afaik it doesn't use the enumerator, it uses the IList interface ( > Count and Item (indexer in c#) ), it needs random access. FYI, I think the grid is calling the base indexer directly, ignoring any "new" indexer.
I implemented a "new" indexer for the inherited class, and using breakpoints I can see that it is never called by the DataGridView when clicking the column headers. Then how, by the life of me, is the grid getting the data from the (possibly sorted) source list? It must be calling the base indexer directly.
The "new" indexer, however, gets called from the instances, when used explicitly as in:
Customers = new Customers(); // an instance of the BindingList class. Customer = Customers[0]; // The new indexer is called and it returns the correct item.
Regards,
-Benton
Bart Mermuys - 16 Jan 2006 19:37 GMT Hi,
>>> It turns out the problems is this: I have the BindingList binded to a >>> DataGridView. On the click of a button, I filter the BindingList, [quoted text clipped - 9 lines] > FYI, I think the grid is calling the base indexer directly, ignoring any > "new" indexer. It's calling IList.Item and IList.Count, this is the untyped version, so not IList<T>. IList and IList<T> are both implemented by Collection<T> from which BindingList inherits.
It's not impossible to override this, but because it's an interface method you're re-implementing and not overriding a virtual function you can't access the base version, so if you override IList.Item you can no longer use ((IList)base).Item.
public class MyBindingList: BindingList, IList { // reimplement interface object IList.this[int Index] { get { return ..... } set { ... } } .... implement all others ... }
--- But i already told you this isn't the best way. You better get the items out of the BindingList and put them into a seperate List<T>. Example:
public class MyBindingList<T> : BindingList<T> { private List<T> invisableItems = new List<T>();
public void SimpleFilter(Predicate<T> FilterPredicate) { // reset filter, add all invisble items to BindingList foreach (T item in invisableItems) base.Items.Add(item);
invisableItems.Clear();
// apply filter, if predicate!=null if (FilterPredicate != null) { // loop all items in bindingList for (int idx = Items.Count-1; idx >= 0; --idx) { // check if it needs to be included or not if (!FilterPredicate(Items[idx])) { // add to invisibleItems invisableItems.Add(Items[idx]);
// remove from bindingList Items.RemoveAt(idx); } } }
// fire reset list (for ui) OnListChanged( new ListChangedEventArgs( ListChangedType.Reset, -1)); } }
Usage:
MyBindingList<Customer> list = new MyBindingList<Customer>(); list.Add( new Customer( ... ) ); list.Add( new Customer( ... ) ); list.Add( new Customer( ... ) );
// using anonymous methods (new in C#) // filter so that only customers whose name start with B are visible list.SimpleFilter( (Predicate<Customer>) delegate(Customer c) { if ( c.Name.StartWith("B") ) return true; // include else return false; // exclude } );
// clear filter list.SimpleFilter( null );
HTH, Greetings
> I implemented a "new" indexer for the inherited class, and using > breakpoints I can see that it is never called by the DataGridView when [quoted text clipped - 12 lines] > > -Benton Benton - 16 Jan 2006 22:27 GMT >> FYI, I think the grid is calling the base indexer directly, ignoring any >> "new" indexer.
> It's calling IList.Item and IList.Count, this is the untyped version, so > not IList<T>. IList and IList<T> are both implemented by Collection<T> > from which BindingList inherits.
> It's not impossible to override this, but because it's an interface method > you're re-implementing and not overriding a virtual function you can't [quoted text clipped - 11 lines] > .... implement all others ... > } Thanks, this is a life saver. I first worried about not being able to use ((IList)base).Item, but later I discovered that I can always access the original list using "base[index]", which is not the IList.this[int Index] I'm reimplementing (though I don't know exactly why). In the end, this is great for what I am doing.
Anyway, seems that after a stall of several days, I'm getting away with this thanks to your invaluable help. I really appreciate your time, honest.
Best Regards,
-Benton
Bart Mermuys - 15 Jan 2006 17:52 GMT Hi,
> Hi there, > > I've googled for hours in search for a filtering mechanism for a > BidingList<T> inherited class. I found several examples for sorting and > searching but none for filtering. I mean filtering within the class > itself, without using BindingSource. Don't think a BindingSource would even help, it doesn't include filtering either.
> Does anyone knows why? Any pointers? I been looking for one too but either we can't find any or nobody has felt like writing one.
A filtering BindingList isn't that simple as a sortable BindingList. A filtering BindingList must include an expression evaluator. You can find lot's of information about expression evalutors but even then it takes some time to get right and implement every feature you need, at a minimum you need:
- can handle different types ( string, int, DateTime, bool, etc) - parameters ( for field names ) - simple operators ( + * - / ) - conditional operators ( == <> < > ) - logical operators ( AND, OR, NOT ) - functions (SubString) ? aggreate ? (optional)
You could bypass the expression evaluator if you want to keep it simple and have some method like Filter which takes a delegate, the delegate would be invoked for each item and the code attached to the delegate must decide whether an item should be visible or not. Similar to Sort( IComparer) except i would use a delegate instead of an interface.
Anyway you do it, the "invisible" items should be put inside a seperate List<> within the inherited BindingList<>.
And another issue is whether you want dynamic or static filtering.
You can find a filtering custom collection based on NET1.1 inheriting from CollectionBase at codeproject: http://www.codeproject.com/csharp/customcollection.asp and a lot of code about expression evaluators can be found at codeproject too.
HTH, Greetings
> Best Regards, > > -Benton Benton - 16 Jan 2006 04:18 GMT >> I've googled for hours in search for a filtering mechanism for a >> BidingList<T> inherited class. I found several examples for sorting and >> searching but none for filtering. I mean filtering within the class >> itself, without using BindingSource.
> Don't think a BindingSource would even help, it doesn't include filtering > either. A BindingSource class can sort, filter, and navigate the BindingList you bind to it, though is an "external" solution. BTW, here's a nice project I found while searching: http://www.gotdotnet.com/workspaces/workspace.aspx?id=ccbb6b50-6c55-4291-b191-f5 c5f80ba122
I really enjoyed your post. Thanks for your insight.
Regards,
-Benton
>> Does anyone knows why? Any pointers? > [quoted text clipped - 37 lines] >> >> -Benton Bart Mermuys - 16 Jan 2006 18:17 GMT Hi,
>>> I've googled for hours in search for a filtering mechanism for a >>> BidingList<T> inherited class. I found several examples for sorting and [quoted text clipped - 6 lines] > A BindingSource class can sort, filter, and navigate the BindingList you > bind to it, though is an "external" solution. You made me doubt, so i had another look. If the list you bind to the BindingSource doesn't support sorting or filtering then neither will the BindingSource.
> BTW, here's a nice project I found while searching: > http://www.gotdotnet.com/workspaces/workspace.aspx?id=ccbb6b50-6c55-4291-b191-f5 c5f80ba122 I downloaded it, seems to be a combination of what i explained, it supports the simple filtering by using an interface IItemFilter. Then there are some classes that implement IItemFilter: PredicateItemFilter which works with a delegate fired foreach item allowing you to include or exlude an item and ExpressionItemFilter (unfortunetaly it's not implemented). The code is also a wrapper for an existing list (so that makes it a little more complicated). All considering i still find it interesting code, thanks for the great link.
Greetings
> I really enjoyed your post. Thanks for your insight. > [quoted text clipped - 43 lines] >>> >>> -Benton
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|