Build Custom Data Bound Business Objects and Collections Talk at DevConnections this morning

I just got finished doing my first talk here at DevConnections in Vegas and I think it went pretty well. Great crowd, good questions, fun topic.

You can grab the slides and demos here: SlidesDemos

The talk highlighted how to define custom objects and collections to make them suitable for data binding, mostly for Windows Forms, but some of it is applicable to ASP.NET as well.

The key takeaways from the talk are:

  • Implement INotifyPropertyChanged on any business entitity type you define that you expect to use in data binding scenarios. This interface defines a contract for the objects to raise PropertyChanged events whenever a property is set on the object. It allows containing collections or bound controls to be notified when the contents of the data object change, which helps with keeping controls synchronized in a form.
  • Use BindingList to create strongly typed collections of objects that support rich data binding. It provides full implementation of IList, ICollection, IEnumerable and their generic strongly typed counterparts for whatever type parameter you provide, and it provides a partial implementation of the IBindingList interface. The part that it implements is firing ListChanged events when items are added or removed from the collection. It also looks at the objects type that you provide as a type parameter, and if it implements INotifyPropertyChanged, the collection will subscribe to the PropertyChanged event on each object and raise ListChanged events with a change type of PropertyChanged whenever the contents of an object in the collection change. These features make BindingList collections work seamlessly with data binding to multiple controls and keeps the controls all in sync.
  • Use my BindingListView class (in the demos and in my book) to get a generic container that supports sorting (both IBindingList based single property sorts and IBindingListView multi-property sorts), searching, and filtering.

If you were there at the end and saw the on-the-fly demo where I didn’t see the saving behavior that I thought I had just implemented, I tracked down the problem. the changes were actually being saved. It was just the way I hooked up the data binding I wasn’t seeing those changes.

In the demo, I used the data sources window to generate a Details view (control collection) bound to a collection of Album data. I changed one of the controls in the collection which was bound to a GenreID property on the Album objects to a ComboBox. I then used the Data Sources window to add data binidng to a Genre object collection to populate the list of Genres in the combo box. This sets up the ComboBox to have its contents determined by the Genre collection, but its SelectedValue property is bound to the GenreID property on the current item in the Album collection – generally exactly what you want to be able to edit a property on one object collection item through a lookup list of values in another collection of objects. The problem was that after I selected a new value in the combo box and saved the changes, then restarted the app, I wasn’t seeing the modified value set for the Album I was viewing in the other controls.

It turns out the problem was just the order that I did the initial binding of the control collection and the combobox BindingSources. In the form load I had added the following two lines of code to bind the control collection and the combo box binding sources:

albumBindingSource.DataSource = Album.GetAlbums();
genreBindingSource.DataSource = Genre.GetGenres();

The problem is that when you set the DataSource, that is when it intializes the bound controls. So I was initializing the data bindings for all of the controls based on the album data, then intializing the combo box of Genres with a new set of data. That set the SelectedIndex of the ComboBox back to zero, so I wasn’t seeing the actual value of the Genre for the current Album, I was just seeing the first Genre value in the Genre collection. The fix is simply to do the initial binding in the reverse order:

genreBindingSource.DataSource = Genre.GetGenres();
albumBindingSource.DataSource = Album.GetAlbums();

Then it works as expected.

Some resources I mentioned in the talk, as well as some additional ones I gave related to after-session questions:

My Book: Data Binding in Windows Forms 2.0, Addison Wesley, January 2006
Rocky Lhotka binding refresh problem post:
Rocky Lhotka article on binding to business objects: Windows Forms Object Data Binding in .NET 2.0,,
My recent article on The Server Side .NET: Build a Data Access Layer with the Visual Studio DataSet Designer, The Server Side .NET, Oct 2005,
My recent article in CoDe magazine: Tackle Complex Data Binding in Windows Forms 2.0, CoDe Magazine, July/Aug 2005,