Bindable LINQ: Windows Forms

Update: SyncLINQ has been released under the name Bindable LINQ, and is available from CodePlex

Last night I spent a bit of time refactoring how SyncLINQ routes collection changed events internally. This was for a number of reasons, but mainly so that I could add Windows Forms support as well as deal with some minor differences in how Silverlight 2.0 beta 1 deals with collection changed events.

The end result of this work is that SyncLINQ now works in Windows Forms!  

Long time data-binders will remember that Windows Forms has always shipped with an IBindingList interface, where WPF and Silverlight prefer new the INotifyCollectionChanged interface. SyncLINQ collections now implement both interfaces, and route changes to the appropriate event depending on who is subscribed to it.

Here’s an example of Task Manager implemented in SyncLINQ:

image

Who’d have thought you could implement a filterable Task Manager using a class with a couple of properties and a LINQ query? :)

I also spent a bit of time working on a class diagram to explain the major areas of the SyncLINQ implementation. Click for a larger version (you might want to save it locally so you can zoom in and out):

image

A question for you:

Since SyncLINQ queries now implement both INotifyCollectionChanged and IBindingList, the same query can be bound to both a Windows Forms UI and a WPF UI.

One downside to this is that WPF actually treats IBindingList as a higher priority than INotifyCollectionChanged. That is, it will subscribe to the ListChanged event rather than the CollectionChanged event. This is a problem, because the events on INotifyCollectionChanged are actually designed to be more efficient than IBindingList.

To solve this, I am considering rolling back some of the changes and not implementing IBindingList, and instead providing an extra extension method and an adapter. For example, in WPF, you could write this:

var query = contacts.AsBindable()
            .Where(c => c.Name.StartsWith(textBox1.Text))
            .OrderBy(c);

While in Windows Forms, you would need to write this:

var query = contacts.AsBindable()
            .Where(c => c.Name.StartsWith(textBox1.Text))
            .OrderBy(c)
            .ToBindingList();

What do you think?

12 Responses to “Bindable LINQ: Windows Forms”

  1. ToBindingList() sounds like an acceptable trade-off to me.

    I don’t know about others, but right now all my Windows Forms applications are still .NET 2.0, so [Sync]LINQ isn’t even an option. I hope to change that before long, but I think it’s fair to make WPF your priority.

  2. So far I have avoided the need for two way binding to linq queries against BO’s in our apps, however knowing it is now an option is quite exciting.

    I think I’d be happy enough to add ToBindingList to win forms queries. Even if i were developing presentation logic for both WPF and win forms UI layers in the same project, I dont think it would cramp my style too much.

    Nice diagram btw!

  3. I vote for the solution since BindingList is not the working horse in WPF.

    Glad to see the major progress of SyncLINQ lately and it’s useful with WinForm, WPF, and Silverlight with any LINQ provider. Wonderful!

    Hope to see Silverlight 2.0 sample soon.

    Cheers,
    Kevin

  4. Hi Jim,

    Although I implement IBindingList, it’s purely for the purposes of raising ListChanged events - the items in the collection are editable but the collection itself is not.

    Being able to add items to the query result (two-way binding) is a possibility, though not something I focussed on (since it’s not really a concept in WPF). I’ll have a think about what it would involve.

    Paul

  5. I’ll first admit that I have very little knowledge of both WinForms and WPF development, as I’m 100% web when it comes to UI, for the last few year.

    I would still vote for ToBindableList(), as lowest-possible-dominator is not a good practice imo, if it hurt the better parts.

  6. What about creating an AsBindableList method to supplement AsBindable? That way there’s no _extra_ call, you just have to add the extra ‘List’ keyword if you want to use it in ye-olde-SWF.

  7. I’d prefer a ToBindableList() extension as this allows you to put off the binding decision until later in the code.

    With an AsBindableList() extension you can’t separate the binding type from the query like this:

    if (checkforwpf)
    somecontrol.DataSource = query;
    else
    somecontrol.DataSource = query.ToBindableList();

  8. Thanks all,

    I ended up going with ToBindableList as you all suggested - I wanted to do that as well, but didn’t want to suffer the wrath of the Windows Forms holdouts :)

    It’s in the latest SVN commit.

    @Norman - I considered it but AsBindable() usually goes at the start of the query rather than the end. I’d prefer SyncLINQ used INotifyCollectionChanged as much as possible between operations, and then plugged an adapter in right at the end. Doing it at the top of the query would mean each one has to speak both event types - not hard, but with the same problems I described in the post.

  9. Very nice works and THANKS for adding support for winforms. I don’t understand all the fuse about WPF. A question are you building LOB like applications with WPF? I have just started a major rewrite of an old VB6 application with about 150 forms. And I have chosen winforms and components from DevExpress.

    Do any readers of this blog know about some god design guidelines for building winforms infrastructur.

  10. […] SyncLINQ for Windows Forms (Paul Stovell) […]

  11. Martin, you should take a look at the CAB (Composite UI Application Block) and SCSF.

  12. The problem with current implementation is that it uses WPF interfaces, defined in PresentationCore & WindowsBase libraries. That makes an application to mix heavyweight stuff from different worlds.

    My suggestion is to abstract all routing logic in some intermediate classes and provide corresponding classes for WinForms and WPF binding logic.

    Personally I hate to reference some assemblies my code will never ever use during runtime just to make some 3rd party library happy :)

    So in general, WinForms version of SyncLinq should not reference INotifyCollectionChanged at all, just IBindingList. WPF could use just INotifyCollectionChanged and probably ignore IBindingList completely…

Leave a Reply