Introduction

The .NET Framework provides several useful classes to support data binding. Unfortunately, these classes are associated with the System.Windows.Forms (SWF) namespace. This is because the usual goal of data binding is to associate a control with a (typically business layer) container. However, there are times when I've wanted to use data binding without pulling in the SWF namespace. Examples include console apps, unit tests, and services. The purpose of this article is to introduce a simple table binding helper that can be utilized without the SWF namespace.

What is Data Binding?

Data binding wires up property change events so that two or more classes can be automatically synchronized when (typically) a property value changes. Data binding is an elegant way of decoupling the presentation layer from the business layer, using events to move data across this boundary. Furthermore, the presentation layer and business layer don't need to know about each other if an intermediary (typically called a controller) is used to wire up the events between these two layers. Similarly, data binding can be used to decouple the data access layer's representation (perhaps in the form of a DataTable) with the business layer (perhaps wanting to map individual rows to class instances).

There are two terms used regarding data binding: simple and complex. Simple data binding is typically used with a container class and a control, where there is a one-to-one relationship between a property in the container and a property of the control. When the container's property value changes, the control's value (usually what's being displayed on the UI) is automatically updated. Similarly, when the control's editable property is changed, the container is updated.

Complex data binding refers to binding controls to a table. For this to work, the data binding mechanism needs to have the concept of a row cursor so that the values associated with a specific row update (in both directions) with the control that is displaying the values. And the row cursor often needs to be automatically updated as the user navigates a list-type control, such as a DataGridView. Hence the term "complex data binding". By watching events in the DataTable and events in the list-type control, UIs consisting of both list controls and discrete controls can be created which automatically track the selected row, handle UI updates when the table is changed, and so forth.

The History of Data Binding

Data binding in .NET 1.1 was initially implemented using reflection to detect events with the signature [propertyName]Changed. For example, a class with a Text property would implement a TextChanged event. The event handler is responsible for retrieving the Text property value and updating whatever object (and the corresponding property in that object) with the new value. Two way binding is achieved by also wiring up an associated event going the other direction.

The problem with this approach is that the event handler doesn't have any way of knowing which property was changed, which makes it difficult (but not impossible) to write a general purpose event handler. The .NET 2.0 Framework introduces the interface INotifyPropertyChanged which requires the implementer to supply a PropertyChanged event. The event signature is the standard "object, args" signature, in this case "args" is of the type PropertyChangedEventArgs, and the single property of this class is the property name. Now the event handler knows the name of the property associated with the event and a general purpose event handler can be easily written. Furthermore, it's easier to test whether a class provides property notification--you can test obj is INotifyPropertyChanged. Conversely, you don't know on "what" properties the class will provide notifications. You do with the .NET 1.1 style, using reflection (assuming that the xxxChanged event is actually correctly used by the associated "xxx" property).

The more "legacy" way of writing a general purpose event handler requires creating a helper object that retains the name of the property and implements the event sink so that the event handler has an instance of the helper object. Confused? The difference is this: with a class that implements INotifyPropertyChanged (and therefore the PropertyChanged event), the property name can be "forgotten" since the event contains the property name. With legacy implementations, you need a container class that retains the property name and also sinks the [propertyName]Changed event, so that the handler can acquire the property name given the instance of what is sinking the event. If you've optimized the code, you don't actually need the property name, you can acquire once and repeatedly use the PropertyInfo instance, but the concept is the same.

Following is a simple class (BindableDataElement) that illustrates the INotifyPropertyChanged interface. I use this class for the unit tests described later in this article. Notice how this class implements both the older style property changed event TextChanged and the newer style PropertyChanged event. Compare the differences. If you want to support legacy data binding in your container classes, you will need to implement both event styles.

Unfortunately, the .NET 2.0 control classes do not implement the INotifyPropertyChanged interface. However, for the purposes of this article, that doesn't matter because the point of this article is to implement table binding without using the System.Windows.Forms namespace (and hence controls).

Thinking about Data Binding

As stated earlier, data binding is typically thought of in the context of bridging the business and presentation layers. Even MSDN's documentation on data binding in .NET 3.0 propagates this concept: Data binding is the process that establishes a connection between the application UI and business logic. Of course, this is on the page discussing data binding in the context of WPF, which is how you'll see data binding always discussed--within the context of the UI.

However, data binding is useful in a non-UI context as well. It's a useful mechanism for associating two classes without either of them knowing about each other (similar to the observer pattern). It's also a useful mechanism for connecting the data access layer (DAL) and its more raw DataTable representation of the data with business layer objects where concrete classes are used as containers for table data.

The .NET Classes

The .NET Framework includes several useful classes for data binding. The premier class in .NET 2.0 is of course the BindingSource class, which implements ten interfaces to support complex binding via list management routines (navigation, sorting, filtering, updating) and currency management (row cursor, change notification, etc.). Whereas previously (in .NET 1.1), a control's DataSource property was initialized to a DataTable or DataView and the form's CurrencyManager (part of the BindingContext) had to be used to manage currency (the row cursor) of controls bound to tables, with the advent of .NET 2.0 the functions of data binding and currency management were exposed in the BindingSource class, which frankly made more sense. Unfortunately, the BindingSource class is still part of the System.Windows.Forms namespace.

In .NET 1.1, the BindingContext property is a member of the Form class, which manages the BindingContext collection class. Whether the data source is simple (single property) or complex (implementing IList or IBindingList) determines what object is returned by the BindingContextItem property--a PropertyManager or a CurrencyManager, respectively. It's a bit of a kludge, because the Position and Count properties of the PropertyManager class have no effect. As mentioned in the preceding paragraph, this approach (the Form managing BindingContext instances which gave you a reference to a base class from which PropertyManager and CurrencyManager were derived) is now essentially obsolete for complex binding--the BindingSource is a much better mechanism.

Fundamental to either implementation is the Binding class which maintains the actual binding between a control property and the property of an object or the current object in a list of objects. What's interesting about this class is that, besides using a property name, you can use a period-delimited navigation path. The navigation path helps you navigate data sets, data tables, class properties, and even navigate across relationships between tables. This magic happens by utilizing a combination of reflection, data set navigation, and currency management of each collection in the navigation path. The only rule is that the final property must resolve to a simple value property or a column in a collection managed by a currency manager.

The TableBindHelper Class

The class I'm going to present here is in no way a replacement to the .NET BindingSource class nor does it have the richness of the Binding class in terms of navigation path support. If you are binding complex types (DataTable, DataView, DataSet objects) to controls, I highly recommend the BindingSource class. What I'm presenting here is a small class that I need primarily to provide some limited complex binding in an environment where I'm not using the System.Windows.Forms namespace, namely unit testing of other components, console applications, and services. The work here extends my earlier article on Understand Data Binding and has some similarities to the article on Object Mapping - The Row Cursor.

Implementation

Management of Columns and Instance Properties

The TableBindHelper has four fields which are useful to understand, as they are the backbone of how the class works.

The first two are obvious--the DataTable instance to which we are providing binding services, and a field to manage the "currency"--the current row. (An amusing story about the term "currency"--when I first looked at the .NET binding classes and saw properties dealing with "currency", I couldn't for the life of me understand why there were properties dealing with monetary values.)

It's the two Dictionary collections that are really of interest. The first, columnBinders, maintains a mapping of columns, by name, bound to properties in a class. The second, propertyBinders, is a map of properties in an instance that are mapped to columns in the table.

The AddColumnBinder method adds entries to these two dictionaries so that the TableBindHelper can update the value appropriately when a change is made to the DataTable or to the instance property.

The first four lines set up the entries in the dictionary. For testing purposes, I decided to implement both .NET 1.1 and 2.0 binding support, and to allow the programmer to force legacy event hooking.

Lastly, if there's a valid row index, the instance property is updated with the value in the column for that row.

The problem is always, what to do with a null or DBNull.Value? I suppose I should have made this method virtual so that you could override the behavior of this method, but I figure, you'd probably just fix it here in the code. Unfortunately, "fix it" probably results in different implementations for different people. Certainly setting val to an empty string is not going to make a numeric property happy when the type converter tries to convert an empty string to a number!

So, add implementation here as you require. This also involves the decision regarding nullable types--if your class uses nullable types, you can avoid the annoying question of what to set the property to when the column value is DBNull.Value.

When the Instance Property Value Changes

Going the other direction is easier because an object type is used as the storage mechanism for columns:

And you'll note here that I'm explicitly setting a null value to DBNull.Value, so it's suitable for transactions to the database.

Unit Tests

I have several unit tests that validate both legacy and the new .NET 2.0 binding processes. The unit tests also do some minimal testing to verify that row changes are properly handled. And of course, the unit tests provide good usage examples, so I will show the entire suite of unit tests here. Notice I don't show you the whole TableBindHelper class, oh no, the unit tests are far more important! By the way, these aren't NUnit tests--these run with my unit test engine, but converting them to NUnit tests wouldn't be difficult.

Conclusion

I hope this article is useful as a starting point for people interested in data binding independent of the System.Windows.Forms namespace. While it is by no means comprehensive, it should be a good foundation for a rigorous implementation, but hopefully it will be useful as is for lightweight binding of classes to the DataTable. It seems that every year or so I end up revisiting data binding for one reason or another. It's a very useful technique, and it's very "rich" in capability, fitting into different architectures and working well with imperative and declarative code alike.

I've published a project on CodePlex that you might want to check out. Rather than a helper for data binding, this is an alternative. You can find it at http://codeplex.com/updatecontrols/.

As opposed to data binding, where you attach controls to properties, Update Controls fire events to get their data. For example, the UpdateTextBox control fires the GetText event, which returns the string to display. The control keeps track of all the data that you access during that event. When any of that data changes, it fires the event again.

The neat thing is that this works through business logic. You can call any method, no matter how deep or indirect, and it will see the data that you touch. So you don't have to implement a binding source or any special interfaces. It's completely automatic, and really easy.