Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Implementing Two-Way Control Binding for Web Forms : Page 5

ASP.NET's native data binding provides only one-way data binding. With a little bit of effort, it's possible to extend the native functionality and provide flexible two-way data binding and a few other simple enhancements that drastically reduce the amount of code you have to write for binding data to controls.

How It Works
To make this simplified data binding code happen requires a little work. The main concept behind it is subclassing and then delegation to worker classes that do the dirty work. The hardest part to using this stuff is to remember to use these subclassed controls rather than the built-in ones.

To see how this simplified data binding code works, let's look at the wwWebTextBox class and see how it subclasses the standard Web TextBox. The code is shown in Listing 1. (There is a little bit of code omitted in Listing 1 that deals with a few unrelated issues, such as password value assignments and rendering error messages. What you see in Listing 1 is the core code needed to implement a two-way data binding control. You can review the sample code for the complete source code).

The key here is the implementation of the properties and methods of the IwwWebDataControlinterface, as defined in Table 1.

Table 1: Definitions for the control properties and methods of the IwwWebDataControl interface.

IwwWebDataControl Property



The object that the control is bound to. This will be a DataSet, DataRow, DataTable/View or it could be a custom object on the form. It can use syntax like Customer.DataRow.


The property or field that the data is bound to.


The property of the control that the binding occurs against.


A format string that is compatible with String.Format() for the specified type. Example: {0c} for currency or {0:f2} for fixed two decimals.


Descriptive name of the field. Used if an error occurs to provide an error message.


Internally used value that gets set if an unbinding error occurs. Controls that have this set can optionally generate error information next to them.

IwwWebDataControl Method



Binds data to the control from the BindingSource.


Unbinds data back into the BindingSource.

If you look at the code for wwWebTextBox, you'll see that there really is nothing there except forwarding calls to wwWebDataHelper, which actually does the data binding.

The class wwWebDataHelperhas all static members. It works by using reflection to evaluate the value in the data source and the control and then by assigning the value to one or the other, depending on whether you are binding or unbinding. To help with the reflection tasks, there's another helper class, wwUtils, which includes wrapper methods to do things like GetProperty, GetPropertyEx, SetProperty, and SetPropertyEx. These methods use the PropertyInfo (or FieldInfo) classes to retrieve the values. The Ex versions provide a little more flexibility by allowing you to navigate through an object hierarchy and by retrieving and setting values further down the object chain. For example, you can use:

wwUtils.SetProperty(this, "Customer.Address.Street", "32 Kaiea")

This is a lot more friendly than the three longer reflection calls you'd have to make to get there.

Let's start with Control binding and unbinding (see Listing 3).

The code starts by retrieving the BindingSourceObjectand tries to get a reference to the object. If that works, it retrieves the Property string. At this point, a check is performed on what type of object is being bound against, determining where the data comes from. If it's a DataSet, use the field of the first row of the table specified in the Property string. If it's DataRow, use the field. If it's an object, use reflection to retrieve the actual value.

Once you have a value, you can assign that value to the property specified in the BindingProperty. But before you can do that, a few checks need to be made for the type of the property and checks for null values that can crash the controls if bound to. Yes, this code actually handles nulls by assigning empty values to display automatically. The assignment of the value is done by reflection using SetProperty(). If a format string is provided, the format is applied to the string as it's written out.

Setting properties in the Property Sheet is much quicker than using a Builder or writing script expressions inside of ASP.NET HTML.
The process of unbinding a control is very similar; it's the same process in reverse, as shown in Listing 4.

This code starts by retrieving the control source object and the value contained in the control held by the BindingProperty field. This is most likely the Text field, but could be anything the user specifies, such as checked for a CheckBox, or SelectedValue for a ListBoxor DropDownList. The BindingSource is also queried for its type by retrieving the current value. The type is needed so you can properly convert it back into the type that the control source expects. This involves the string to type conversion, including the proper type parsing, so you can use things like currency symbols for decimal values, and so on. The Parse method is quite powerful for this sort of stuff. Once the value has been converted, reflection is used to set the value into the binding source field based on the type of object you're dealing with. DataSets, Tables, and Rowswrite to the Fieldcollection, and objects and properties are written natively to the appropriate member.

These two methods are the core of the binding operations and are fully self-contained to bind back controls. This process lets you bind individual controls and the methods are then called by each control's BindData() and UnbindData() methods respectively, as shown in Listing 1.

The next thing you need to do is bind all the controls on a form so you don't have to bind them individually. This is an easy concept. You know that all of your controls implement the IwwWebDataControlinterface. So it's fairly easy to navigate through the Web Form's Controls collection (and child collections) and look for any controls that implement the IwwWebDataControlinterface and then call the BindData()method. Listing 5 and Listing 6 show the FormBindData() and FormUnbindData() methods that do just that.

As you can see, FormBindData() runs through the controls collection and checks for the IwwWebControlinterface. This method is recursive and calls itself if it finds a container and drills into it. It makes sure that the entire form data binds. When a control is found, the BindData() method of the control is called dynamically using reflection.

When an error occurs, the text of the control is set to a Field binding error so you can immediately see the error without throwing an exception on the page. This is handy, as you don't get errors individually. The error is most likely to be a developer error, not a runtime error, so this handling is actually preferable.

Unbinding works in a similar fashion as that shown in Listing 6.

The code in Listing 6 is very similar to the FormBindData() method. The difference here is that you call the UnbindDatamethod and that you deal with errors on unbinding differently. It's much more likely that something will go wrong with binding back then with binding, as users can enter just about anything into a text box, like characters instead of numeric data or non-date formats in date fields. These user errors throw an exception in the control's bind back code, and are handled there.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date