Complex databinding in detail

Currently, I am working on the ListObject control, one of the view controls shipped as part of VSTO 2005. It allows an office developer to perform complex databinding in an excel worksheet.

When I started working on ListObject, I realized I needed to have a very sound understanding of complex databinding. That got me started exploring. I will discuss details of what I found in this post.

So what is complex databinding? In a nutshell, complex databinding is when you bind a control (eg. datagridview, listobject in excel) to a set of data items (a collection, IList, a DataTable). For example, a ListObject has a Datasource property which can be set to an ArrayList of strings or a DataSet. What makes it different from simple databinding? In simple databinding, a single property of the control (TextBox.Text) is bound to a single value in the data model.

What is the great thing about databinding? Databinding in .NET is a clean way of separating the data from the view. I cannot overemphasize how important this is and how it can lead to a much cleaner design.

Lets dig into more details. Whenever I hear complex databinding, I seem to be hearing a number of "infrastrcture pieces" associated along with it: CurrencyManager, BindingContext and RelatedCurrencyManager. When I say infrastructure pieces, I intend to highlight the inner workings of complex databinding which apply to any control that implements complex databinding.

CurrenncyManager
Any datasource that is bound to a control has a currency manager associated with it. The interesting thing about currency managers is that if you bind a control to the same datasource then they will have the same currency manager. For example,

listbox1.DataSource = dataset1; 
datagrid1.DataSource = dataset1;

In this case, the underlying currency manager is going to be the same. See this link for more details.

So what does the CurrencyManager do? As the name suggests, it manages the "current" position of the underlying data source. Add a datagrid control and ListObject onto the Excel design surface and bind them to the same datasource. Change the selection on the ListObject and you will see it change on the datagrid control too. Thats the currency manager at work.

BindingContext

In .NET, there is a notion that a number of controls can be in sync. This is useful in creating Master Detail Relationships among databound controls. For example if you have VSTO ListObject showing departments in a company, and anoter ListObject bound to the employees. Then these two controls can be linked in a master-detail relationship to show the employees in a particular department. This is facilitated by the use of a shared binding context.

Every form or worksheet (in case of Excel host items) has its own BindingContext object. For each data source in the form there is a CurrencyManager object associated with it. Since there may be multiple data sources in a form, and therefore, more than one associated CurrencyManager objects, BindingContext object enables you to retrieve any particular CurrencyManager object associated with a datasource. This is done as follows:

CurrencyManager cm = this.BindingContext[dataSource, dataMember] as CurrencyManager;

Therefore, BindingContext manages a set of CurrencyManager objects on a form. Now the obvious question is : Can we have more than one CurrencyManagers for the same datasource? This is possible by creating separate BindingContext objects

RelatedCurrencyManager

There is more to it than meets the eye. The magic of Master-Detail relationships being bound accross different controls, works because of an entity called the RelatedCurrencyManager. This is totally an internal class in Winforms and is not exposed to the developer.

So when does the RCM get created? It gets created whenever a binding is made to a relation as it needs to be done for master-detail relationships. For example, Deparement table and Employee table are related by a relation entity called EmpInDept.

Therefore, when you do this:

ListObject1.DataSource = ds;

ListObject1.DataMember = "Department";

ListObject2.DataSource = ds;

ListObject2.DataMembers = "Department.EmpInDept";

Internally, now an RCM is created to capture the relationship Department.EmpInDept and a CM is created to track Department table. The CM is tied to the RCM in such a way that when the position on the CM changes, RCM is updated to a new list of data. For example, you select Finance department in ListObject1, the corresponding employees will be populated in ListObject2.

References:
Really complex databinding: ITypedList with weakly typed collections
Databinding in Windows Forms
Consumers of Data in Windowns Forms
Roadmap for Windows Forms Databinding (Q313482)