Rebinding datagrid's datacontext

Jun 9, 2009 at 10:32 PM

I can't seem to find a way to do this.  I create a datagrid whose datacontext is initially filled with rows from a table.  I have implemented a search functionality that will return some rows based on a condition.  Suppose I want to display only those rows, how do I destroy the initially created datacontext and add the newly filtered collection?

I naively started doing it like this:

IEnumerable<MyType> rows = datagrid.Items.Cast<MyType>();

IEnumerable<MyType> filteredRows = rows.Where(row => row.someCondition == true);

how do I now make my datagrid display only the filteredRows?  Just doing:

datagrid.DataContext = null;

datagrid.DataContext = filteredRows;

doesn't work (it even smells stupid for some reason).

I also need to do the reverse (once I get this working).  Some buttonclick should allow the user to "clear" the search results and re-plug the DataContext back to "rows" (in the above snippet).

What am I missing?


Jun 10, 2009 at 6:58 AM

There is items filtering support built into the ItemsCollection (IIRC) base class in WPF. What you want to do can be accomplished by setting dataGrid.Items.Filter to an appropriate function, for example (written from memory and I don't use delegates much so the syntax may be slightly off, but you get the idea):

dataGrid.Items.Filter = delegate(object row) { return (row as MyType).someCondition == true; }; // set filter

dataGrid.Items.Filter = null; // clear filter

Basically, you write a function that takes a single row object and returns true or false indicating whether that row should be included in the displayed collection, then assign that function to the Items.Filter property. The complete collection is left intact and can be accessed with no additional hassle and you don't have to merge the collections manually, as the filtering is purely a function of the view.

Jun 10, 2009 at 2:52 PM

Hi Mikj

Thanks for your response.  I did look at the Filter property but I couldn't figure when that property is called -- in other words, how do I trigger that delegate to execute?  Or is it that the mere Setting of the property causes the delegate to execute?  I will try it out when I get to work today.

Jun 10, 2009 at 4:37 PM

I tried to set the Filter property and this is what I got (partial stack trace).  It appears I am not allowed to set that property.  Why?


System.NotSupportedException was unhandled by user code

  Message="Specified method is not supported."



       at System.Windows.Data.CollectionView.set_Filter(Predicate`1 value)

       at System.Windows.Controls.ItemCollection.set_Filter(Predicate`1 value)

Jun 10, 2009 at 5:01 PM

I tried this approach:

It appears that the datagrid is making room for the filtered records -- that is, I can see the rows being drawn although they are squished very close to each other but I don't see the actual data.  How could I be wasting 2 days on a simple problem like this>?

Jun 10, 2009 at 6:49 PM

I got it to work by following the example in the link I posted above.

The problem I ran into was I was filling the DataSource with incompatible types each time I wanted to update it.  First time it got initialized was with type Table<> returned by LINQ-To-SQL's GetTable<> method.  Then when I filtered it I happened to pass IEnumerable<T> to it.  It looks like its not enough if your data happens to implement some common base/interface.  You need to pass in precisely the same type that went in.  I punted a bit and normalized everything that goes into the DataSource as an instance of List<T> and everything now seems to work just peachy.

Wonder what else I will run into.