Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Windows Forms / WinForm Controls / January 2006

Tip: Looking for answers? Try searching our database.

Filtering a BindingList<T> is not possible?

Thread view: 
Enable EMail Alerts  Start New Thread
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.