Introduction

These tutorials describe how to map your classes to your tables manually (rather than with an automated tool like SqlMetal) so that you can have support for M:M relationships and data binding against your entity classes. Even if you do choose to auto-generate your classes, understanding how these techniques work will allow you to expand the code to better fit your application's needs and to better troubleshoot issues when they arise.

The purpose of this final article is to complete the introduction to LINQ to SQL by showing how to make your LINQ to SQL classes work with WPF data bindings.

Getting Started

This article builds on top of: A LINQ Tutorial: Adding/Updating/Deleting Data, to add INotifyPropertyChanged events to your entity classes so they'll work with WPF's data binding. Please refer to the latest version of that article to see how the application has been setup.

Simple Data Binding

WPF data binding allows you to bind to any CLR object, including the classes you've mapped to your tables with LINQ to SQL. Let's start with a quick look at how it's used in the attached Book Catalog application.

The main window, BookCatalogBrowser.xaml, displays a list of book catalog items in a ListView named Listing (see the bottom of the file):

This is how each Category instance within Listing's list will be displayed. The DataTemplate itself is selected based on the data type (DataType="{x:Type LINQDemo:Category}"), and everything within the template is bound to an individual Category instance.

It displays that Category's data via bindings:

The Category's name: {Binding Path=Name}

The Category's list of books (for a ListView): {Binding Path=Books}

Each book's title (for an individual book in the ListView): {Binding Path=Title}

This results in a list of categories, each one displaying their name and list of books:

Updating the Display When the Data Changes

This works great... until you try to update the data and it fails to get reflected in the UI. Even telling the data bindings to refresh fails to display any changes at all. Everything just seems broken.

The problem is that data binding requires the objects its bound to to provide notifications whenever they change. You can fix this by implementing the INotifyPropertyChanged interface on your classes.

Implementing INotifyPropertyChanged

In order for WPF data binding to automatically reflect data updates, the objects it binds to need to provide change notification to signal when their values have changed. The most common method for doing this is for your classes to implement the INotifyPropertyChanged interface to report changes to their data.

Implement Interface

In A LINQ Tutorial (Part 1), we created classes for Book, Author, and Category, and mapped them to their database tables.

Let's walk through adding the INotifyPropertyChanged interface to your classes using Book as an example.

1. Add the INotifyPropertyChanged interface to the class declaration

[Table( Name = "Books" )]
publicclass Book : INotifyPropertyChanged

2. Add a public PropertyChangedEventHandler that callers can use to register for change notifications

publicevent PropertyChangedEventHandler PropertyChanged;

3. Add the OnPropertyChanged method to notify callers of changes

This method will check to see if there is a PropertyChanged delegate and, if so, invokes that delegate, passing it the name of the field that has changed.

Call OnPropertyChanged() for Each Public Collection (M:1 and M:M) [Association] Attribute

Collection associations (e.g., Book.Categories and Book.Authors) need to do two things:

Return a collection that implements INotifyCollectionChanged.

Call OnPropertyChanged() whenever the collection changes.

Step #1 is used by WPF when it binds to the collection to determine what has changed. For example, the list of Category.Books we bind to when displaying a Category's data.

Step #2 is used when WPF binds to your object to determine when it changes. For example, if Category.Name changes.

M:M Collection of Reference Associations

In A LINQ Tutorial (Part 2), we set up our M:M public classes (e.g., Book and Author) to return an ObservableCollection, which already implements INotifyCollectionChanged, so Step #1 is already done for Book (as shown below) and for Author:

When you create the collection, you register to receive notifications for it (authors.CollectionChanged += AuthorCollectionChanged). This will call your AuthorCollectionChanged method whenever the collection is changed.

Update AuthorCollectionChanged to call OnPropertyChanged() at the end:

Updating the Display When the Data Changes: Once More With Feeling

The attached BookCatalog application includes an EditDetails.xaml UserControl to allow editing any of the LINQ data types.

I'm sure I got entirely too clever for my own good here in trying to handle Books, and Authors and Categories using the same set of methods and UserControls - so I'm not suggesting you model your designs after what is here. But I hope it serves its purpose by providing an example of how you can data bind to LINQ to SQL classes and make sure all of the data is synchronized throughout your application.

In EditDetails.xaml.cs, there is a BindDataToEditForm() that sets up the binding from the UserControl to the dataItem to edit (this could be a Book, Author, or Category):

One way to handle this is to prevent that scenario from occurring -- don't allow a removed relationship to be re-added until after you call SubmitChanges() to persist the deletion. Then, you're free to add it back without error.

The Book Catalog application does this. If you open a Book to edit and delete one of its authors - you simply aren't given the choice to re-add that author until you click the Save button. The same is true on the other side when editing an Author to change which Books they have.

Note that this is only the case for M:M Join records that you remove with a separate DataContext, as described in A LINQ Tutorial (Part 2). There are no limitations to, for example, removing and then re-adding the same book to a Category since this is a M:1 (rather than M:M) relationship.

A Note on the Design

I purposefully chose to provide the View with direct access to the entity classes so that it would be as clear as possible of an example for how the bindings and DataContexts work in an application.

Obviously, in a real application, you'll want to put a layer between your view and the model. You can put your business logic there. You can also hide the details of working with the DataContext (e.g., when to refresh, when to call SubmitChanges()) there, so the view doesn't have to understand anything about LINQ to SQL.

About the Author

She's been developing custom software applications, wearing every hat imaginable, since 1994. Although, technically, she got her start at the age of 8 when her father brought home an Atari 800. In the evenings, they would sit together and type in the machine code from the Atari magazines – because that was the way serious geeks got their computer games!

Today, she works for Microsoft as a Developer Evangelist to the startup community - helping them to create the next generation of software.

I have a question as to applications in multi-user environment. How can Linq-SQL be used to ensure that the data being shown is current? Or will we still have to synchronize/refresh the data periodically somehow when the underlying data has changed on the sql server (e.g) ?

I really love your article! It's very informative and concise at the same time. I'm working on a new project and this article has helped me immensely.

I do however have a question regarding exposing the Association Table. My Association table has a data member and so when I databind my user interface I'm using the ICollection of the Association table and not the ObservableCollection of just Author objects i.e. My code uses the equivalent of

That in itself is all fine. My problem is when I remove the mapping, the ICollection BookAuthors does seem to fire off any notifications to the UI to let it know that one or more items have been removed. I've tried changing ICollection to ObservableCollection but that seems to cause errors when SubmitChanges() executes.

Is there any way I can work around this so that a delete will automatically notify the UI?

First, thank you very much for taking the time to write such a fantastical series of articles. I find in genuinely heartening (from someone that works in financial services!) that people give up their own time to help others (especially those with knowledge far below their's) share in their knowledge - and clearly you thought through carefully the best way to structure this introduction to (to my mind) a very opaque subject matter.

I've been messing about with the linq to SQL tool not having the faintest how it was working underneath and now I think I might possibly just maybe know what's perhaps happening some of the time!

Which is huge progress but alas I think I need to read a lot more before I'll know enough for what I want to do.

From the article itself and the responses you've made in the comments section I thought I might try and appeal to your clearly very generous nature and request some advice from yourself.
At the moment I'm attempting to build my first real user application (having build hundreds of modules in VBA in Excel/Access and one or two in .Net) and I'm currently a bit stuck on these points

a) having UI update when rows are ADDED to a "linq to SQL" datatable eg how the Dickens does your application display an added Book eg in BookCatalogBrowser.xaml from EditDetails.xaml (is it just a sort of manual refresh using the Displaylist method in BookCatalogBrowser.xaml.cs)?

b) working out how to allow (for a multi-user system) for users to be informed when other users made changes to data they are viewing

Do you know of any reference material that would cover these (and databinding more generally with linq to SQL) in a way a dummy like me could follow?

Abby, quite the presentation, isn't it.
The truth is I have not very often read anything, anywhere this constructive
and layered in such a well mannered way, to instruct someone into a complex
subject like this.
It is not the subject itself, but really the way you explain it all
which struck me as fantastic.

=====================================================
I also implemented a middle layer between my view and the auto-generated model. I have a ComponentRepository.cs and a Component.cs.
I've been trying to bind the data to the UI so that my UI will automatically update to reflect changes in the database with no success. By looking at your post, it sounds like I have to implement those partial functions, but i'm not sure if that will solve my issue. I also read about SQLDependancy/Query Notification/caching etc.... But still very confused.