Notes on Data Binding in .Net Winforms

 

WinForm application development is a lot easier than the days of doing Windows Desktop application development in C++ and MFC.  Yes there were other ways of buidling Windows Applications, such as VB etc but while they provided a RAD approach they were quite crappy with regards to OO design and just sheer capability.  .Net and Winform application development provides most (not all) of the flexibility you had in the C++ MFC world.  But this does not mean it is without its own quirks.

This article is a bunch of notes I made while working with data binding and BindingNavgators.  I will update it as I learn more or have more to say.

One nice functionality is the BindingNavigator.  It provides a toolbar required for navigating through data and provides functionality to bind all controls on your form to the same data source as the navigator.  As a result you can do the next, previous, delete, add new, edit etc with great ease.  Not terribly difficult to do in MFC but unlike in MFC I no longer have to create a toolbar and handle all navigation events etc.  So all in all this is a very convenient feature.

However, aha! you must have known there is a catch.  The data binding and BindingNavigator functionality has its own quirks.  In this article I intend to talk about some of these and propose ways to deal with them.

  • Data binding with primitives
  • Always initialize data in classes that are bound.

Data binding with primitives

I find this to be one of my biggest problems with how the data binding has been implemented.  You can bind to an object and then display data from a property of that object.  So if you had a DataGridView or a ListView in which you wish to display string contained in a String[], StringCollection, or List<string>, well you cannot.  Because strings do not have a property that return the string itself.  Actually you can bind a string to a control.  It will display the length of the string as Length is the only property on the String object.

What this means is that you have to encapsulate your primitives (in this case string) into another class, and give that class a property to return the string value.  This can be a pain if what you are receiving is a large string collection of some sort.  Data received by an application is not always controlled by the developer of the application.

So if you had an XML like:

<DATA>

<ITEM>One</ITEM>

<ITEM>Two</ITEM>

<ITEM>Three</ITEM>

</DATA>

To read the above if you created a class Data with a List<string> with the items in it you could get into trouble.  The correct way would be to create a class Data with a List<Item> and class Item with a property callled Value. 

Wrong Way
class Data {
	List<string> _items;
}

Right Way
class Data {
	List<Item> _items;
}

class Item {
	private string _itemValue;
	public string Value {
		get....
		set....
	}
}
									

So if I say that creating the second class Item is the right way then why am I complaining?  Its not so much of a complaint as much as it is a warning.  As mentioned earlier, sometimes we receive data and cannot dictate what we get, in which case you may have to loop through the string collection and encapsulate each string.  And sometimes we get lazy and we do not create the class to encapsulate even when we have control over the code.  Also xsd.exe (a tool that will create classes for you based on an XSD) will generate string[] rather than the final level of encapsulations.  So this is something you should keep in mind.

Always initialize data in classes that are bound

Another strange quirk I found is how the data binding code behaves when you have un-instantiated class data.  When you bind a control in a form to a BindingSource you do so by binding a property of the source to a property of a control.

For example:

//This will bind a text box called textBoxUsername by binding its Text property to the UserName
//property of the binding source.
textBoxUsername.DataBindings.Add( new Binding( "Text", myBindingSource, "UserName" ) );

//Here I bind a ComboBox SelectedValue property to my Binding Source categoryName property comboBoxCategory.DataBindings.Add( new Binding( "SelectedValue", myBindingSource, "CategoryName" ) );

This BindingSource myBinding source is assigned to data using its DataSource property.

class Data {
	private List<SubData> _subData; //THIS IS BAD
//	private List<SubData> _subData = new List<SubData>(); //THIS IS RIGHT
	public List<SubData> SubData {
		get...
		set...
	}
}

class SubData {
	private string _dataValue;
	public string DataValue {
		get....
		set....
	}
}

//Now in some Form you may have code like

myBindingSource.DataSource = _someLocalData.Data;
								

 

Always add one item to a collection or Disable your UI

If you have a list add one blank item to it.  This way when you display your form you are on the first item.  If you do not do so you will be on a non existant item and the user will have to click + on the navigator to add a new item.  Many users start typing in data without clicking the + on the navigator.  By adding a blank item you are providing your user with a better experience.

Alternatively, disable all controls except for the navigator on your UI.  Thereby forcing the user to click on the add new item (+) before typing in any data.  So check your datasource and set controls to Enabled = false if datasource count is zero.


|My Home| |Tech Talk|