Thursday, September 20, 2007

Linq with Xceed's WPF Grid

Binding a read only Linq data table to Xceed's WPF data grid couldn't be easier, but things get a little trickier when you want insert/delete/update functionality.

The general recommendation (from Xceed's samples) is to implement a derived IBindingList collection class to provide the behaviour yourself.

Sounds like a lot of work to do something simple, especially if you want to bind to a lot of different objects - so here's a generic one I've prepared.

BTW: I haven't seen any articles on the web regarding best practice with this, so I'd love any comments if there is a better way.



class LinqList<T> : BindingList<T>
{
ITable table = null;

public LinqList(ITable table)
: base(table.OfType<T>().ToList())
{
this.table = table;
}

protected override object AddNewCore()
{
T item = (T)base.AddNewCore();

if (table != null)
table.Add(item);

return item;
}

public override void EndNew(int itemIndex)
{
base.EndNew(itemIndex);

if (itemIndex >= 0)
DataSource.Context.SubmitChanges();
}

protected override void RemoveItem(int index)
{
if (table != null)
table.Remove(this[index]);

base.RemoveItem(index);
}
}


My first code draft uses the BindingList as a base class (to avoid implementing everything myself) and takes a Linq data table as a constructor parameter.

Notice the OfType() call in the constructor, this provides basic support for inheritance with Linq, but more on that in a later post.

I use a singleton to store my Linq data context (DataSource.Context) to call SubmitChanges() after adding a new item.



static class DataSource
{
static DataSource()
{
DataSource.Context = new MyDataContext();
}

static public MyDataContext Context { get; set; }
}


Binding to Xceed

Simply bind an instance of this class to your data grid, and you're almost set!

See Part II for some changes that need to be made to the Xceed grid, to make this binding easier.

3 comments:

rei said...

This took me a while to figure out too, but it turns out that you can just call GetNewBindingList() on the LINQ table.

The only thing you have to do manually is call SubmitChanges(). I'm still trying to figure out the best timing to do this, though. You can't use the IBindingList.ListChanged event, since at that point the item is added to the list but the properties aren't set yet.

Luke Marshall said...

Thanks rei! Yes I found the GetNewBindingList() on the table, but unfortunately it's not available for queries. :(

In terms of SubmitChanges() I'm keen to look at WPF SP1's new transactional interface - IEditableCollectionView.

Make sure you have a look at BindableLinq - it's basically what I started on, but on steroids :)

net performance said...

Binding to IList collections enables the grid to create rows at the time of binding. Such collections usually contain a certain number of objects that don’t change during application execution. Use of these collections saves memory used by the application.