WPF: DataBinding with any object, Including LINQ/ADO.NET Entity FrameWork

Posted on 2/19/2007 @ 12:53 AM in #Silverlight and WPF by | Feedback | 20609 views

(Totally random & off topic: Before I start, here is a NSFW video of Britney shaving her head, it gets really funny right around 00:40)

I am a big data geek. I feel any platform that comes out, absolutely must master the "data" story well, because 99% of the applications that will use that platform, *WILL* have a database, and objects behind it.

Now, I have blogged about WPF DataBinding before (basic scenarios, and custom objects). To make the long story short, WPF requires either static variables, elements, classes with dependency properties, or something that implements INotifyPropertyChanged, in order to do a successful 2 way data binding. If in case your objects do not meet any of these criterion, you could still use WPF databinding as a "read only/display only" mechanism using the "OneWayToSource" (Target to Source) BindingMode. I had explained this in an earlier blogpost.

Here is the problem however. Many of your custom objects won't meet this criterion. LINQ resultsets are IQueryable<T>, so they won't support the 2 way databinding story well. Now, in a chit chat with MSFT, I have raised this to MSFT as a potential issue, and Microsoft is working on having explicit support for binding, and probably will make it available in an upcoming CTP. But as it turns out ADO.NET Entities do implement INotifyPropertyChanged, so those should be fine.

Anyway, that is the future - let us talk about today. So, what is the standard databinding interface in .NET anyway? IBindingList. So the Q is, if your custom business objects talk in terms of IBindingList, and hopefully ADO.NET eF objects also one day implement IBindingList (or similar), how could I leverage such objects, in a WPF World?

The answer is, keep this class in your backpocket - System.Windows.Data.DataSourceProvider.

As you can tell from the above picture,

 - DataSourceProvider implements INotifyPropertyChanged, and
 - There are two implementations of it available out of the box, ObjectDataProvider and XmlDataProvider.

(.. and, you can be pretty much assured that our dear friend Rocky Lhotka will be writing a CSLADataProvider one day in the near future).

Howzitwork?

I intend in demonstrating the XmlDataProvider in a different blogpost under a really really cool idea (stay tuned), so in this blogpost, I am going to demonstrate the more generic "ObjectDataProvider" instead.

The aim of the game here is, to create a completely custom object, and be able to do 2 way data binding on that object. So here goes.

The first step is to create a custom business object, I choose to create a custom business object called "LocalTimes", which inherits from List<LocalTime>. LocalTime is a custom class that has 2 properties Place (string) and Time (DateTime). The idea being, I'm trying to create the equivalent of what you see in many hotels - a bunch of clocks telling you local times around the world.

Here is the code for these classes -

public class LocalTimes : List<LocalTime>

{

    public LocalTimes()

    {

        this.Add(new LocalTime("New York", DateTime.Now));

        this.Add(new LocalTime("Chicago", DateTime.Now.AddHours(-1)));

        this.Add(new LocalTime("Denver", DateTime.Now.AddHours(-2)));

        this.Add(new LocalTime("Los Angeles", DateTime.Now.AddHours(-3)));

    }

}

 

public class LocalTime

{

    private string place;

    private DateTime time;

 

    public LocalTime(string _place, DateTime _time)

    {

        place = _place;

        time = _time;

    }

 

    public DateTime Time

    {

        get { return time; }

        set { time = value; }

    }

 

    public string Place

    {

        get { return place; }

    }

}

Now, I am going to create a simple XAML file with the <Window> element as the root, and in it's Resources, I am going to add an instance of "ObjectDataProvider" as shown below -

<Window x:Class="WPFApp.Window2"

 ... some other goo I took out ...

    xmlns:custom="clr-namespace:WPFApp"

    >

  <Window.Resources>

    <ObjectDataProvider x:Key="localTimes" ObjectType="{x:Type custom:LocalTimes}"/>

  </Window.Resources>

  <Grid>

  </Grid>

</Window>

 

As you can see, I am referncing the class I just wrote using the xmlns:custom namespace, and I am using the ObjectDataSource to create an instance called "localTimes".

Okay, next I'm going to show this data in a ListBox. This is shown as below -

<Grid>

  <ListBox

    ItemsSource="{Binding Source={StaticResource localTimes}}"

    >

  </ListBox>

</Grid>

Okay, so that is interesting, I used DataBinding to DataBind the ObjectDataProvider instance to the ItemsSource property of the ListBox. Highly Highly Interesting.

Now at this time, if you run the application, it will look like this -

So each ListItem shows the "ToString()" representation of the Object it is attempting to display. Well, that ain't too useful.

What is missing is, a custom mechanism to represent my custom data - i.e. a custom template for my data.

In order to acheive this, go ahead and create a DataTemplate under resources as shown below -

<Window.Resources>

  <ObjectDataProvider x:Key="localTimes" ObjectType="{x:Type custom:LocalTimes}"/>

  <DataTemplate x:Key="ShowTime" DataType="WPFApp.LocalTime">

    <StackPanel Margin="10">

      <TextBlock Text="{Binding Path=Place}"/>

      <TextBox Text="{Binding Path=Time}"/>

    </StackPanel>

  </DataTemplate>

</Window.Resources>

.. and reference this DataTemplate, as the ItemTemplate for the ListBox as shown below -

<Grid>

  <ListBox

    ItemsSource="{Binding Source={StaticResource localTimes}}"

    ItemTemplate="{StaticResource ShowTime}"

    >

  </ListBox>

</Grid>

Now run the app, it should look like this -

WOOHOO!!! I just databound with a completely custom object.

Okay, now here is the ultra cool thing. Go ahead and set a breakpoint at the "Setter" for "Time" in LocalTime, and modify the time for "New York", what do ya see? -

OH YEAH BABY!! Breakpoints are gettin' hit - we have just acheived 2 way data binding with a completely custom business object. This approach will also work with IQueryable<T> and ADO.NET Entity Framework objects. Also, since DataSourceProvider implements INotifyProvider, you can implement code in the "Presenter" of your object, to notify the UI if in case you have a "Push" data to the UI scenario.

Ultra Neat!

Read more about ADO.NET EntityFramework and WPF DataBinding.

Sound off but keep it civil:

Older comments..


On 6/27/2007 11:00:00 AM Praveen said ..
Good one. Would like to havean email on subsequent writings on WPF.


On 2/6/2008 4:42:25 AM vijaya krishna said ..
hi ,

i read u r bolg it so good, do u have any blogs or vedio files related to databinding if u had


could u plz give me the url of that

regards


vijaya krishna


On 2/7/2008 1:57:27 PM Dan said ..
This is a great post. It took me a while to find a simple example of databinding to custom data objects before I came across your blog. Other examples were using static data declared in XAML or using databases, etc. This showed binding to a custom array quite well. Thanks!


On 6/28/2008 12:41:49 PM Michael said ..
Hi,

First of all, I think your blog is really great!

I have some questions that I can't find solutions for in the Internet.


I hope you can help me.

1. In this post you use the default constructor of LocalTimes. How can I use non-default constructor OR use some object from code-behind (in this case I could initialize it on Load event of the page and use it inside the XAML).


2. I want to create a DataTemplate that will contain a button - how can I add Click event to this button (where the event handler method should be placed).


3. I have many buttons and I want to handle their Click events in a single method. How can I acchive it? Is there a way to send a parameter to the Click handler method?

I will really appreciate your help. It will help me a lot with my final project in the College.

Thanks in advance.


Michael.


On 4/11/2009 1:49:05 PM Mikant said ..
THANK YOU A LOT!! It works great for me!! To find such a simple and good solution I RTFM'med and coded for 20 hours ))


On 12/7/2009 6:25:25 AM Ankit said ..
Very informative post for beginner's in WPF. Thanks


On 12/15/2009 4:05:45 PM Faisal said ..
Thanks for the great example. I have a follow-up question. Lets say you want to reference the localTimes object in your code behind. The idea is that the UI will populate this object which you can use as is in your code behind. How can you do that since the object seems to be instantiated within the Resources?