Click here to Skip to main content
15,883,901 members
Articles / Web Development / ASP.NET
Article

Two way data binding in ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.68/5 (69 votes)
10 Jun 20045 min read 311K   4.7K   116   51
How two use the design time services to provide 2 way data binding in ASP.NET

Image 1

Introduction

Aren't you tired of writing code like this in your WebForms?

C#
...

// populate the webform with the customer data
lName.Text = cus.Name;
lSurname.Text = cus.Surname;
lEmail.Text = cus.Email;
lAddress.Text = cus.Address;
lAge.Text = cus.Age.ToString();

...

// get the customer data from the webform
cus.Name = lName.Text;
cus.Surname = lSurname.Text;
cus.Email = lEmail.Text;
cus.Address = lAddress.Text;
cus.Age = Int32.Parse(lAge.Text);

...

Me too. Unfortunately ASP.NET databinding is only one way so it isn't useful to avoid writing the above code (You can avoid some code using the DataBind method, but not all). After reading this article you'll be able to turn the above code to something like this:

C#
...

// populate the webform with the customer data
bindingManager1.BindToWebForm(this);

...

// get the customer data from the webform
bindingManager1.BindFromWebForm(this); 

...

Background

The ASP.NET data binding mechanism works only in one way: When you add a databinding to an ASP.NET WebForm in design time, Visual Studio .NET adds a databinding expression to the ASPX file (<%# %><%# ... %> ). When the WebForm is requested for the first time, the ASPX file is parsed, JIT compiled and executed. For each data binding expression in a control, a handler is added to its DataBinding event. The DataBinding event is fired when the control's DataBind method is called, and the handlers added by the ASP runtime evaluates the data binding expression and performs the actual data binding. So far, so good.

At runtime we can only rely on ASP.NET to do one way data binding. If we only want to display information this works fine, but if we need to get data from a form, we have to get the values from the controls ourselves, which is a non-orthogonal mechanism and a tedious task.

If we were able to get the data bindings at run time, we could use reflection to perform 2 way databinding. However there is no way to get the data bindings at runtime. Of course, we can add properties in our controls to store the data bindings in order to fix that problem but i don't like that idea.

What to do then? Thanks to the design time architecture and reflection you'll have 2 way data binding without modifying any control (see Points of Interest).

Using the code

Using the BindingManager in order to have 2 way data binding is very easy:

  • Add the BindingManager component to the toolbox.
  • Add a BindingManager component to a WebForm.
  • Use the designer to set the databindings.
  • When you need to load the WebForm with your data call to the BindingManager's BindToWebForm method.
  • In order to get the data from the WebForm, you have to call to the BindingManager's BindFromWebForm method.

And that's all!

Sometimes you don't need 2 way data binding in all controls (for example, in a form to show/update customer data you can have a label that shows when was the customer account was created). If you click on the BindingManager component, and locate the data binding in the DataBinding collection you can set the TwoWay property to false to provide one way support only.

Points of Interest

How does the BindingManager work?

As we said before, there's no way to access to the data bindings at run time. Luckily for us, in design time, we can get the data binding information because the Control class implements the IDataBindingsAccessor interface. IDataBindingsAccessor has 2 properties: HasDataBindings and DataBindings, that can be used to obtain the databindings. The BindingManager stores the data binding information in a collection (DataBindingInfoCollection) and thanks to the services offered to the component designers, we could monitor any component change to keep the data binding information updated using the IComponentChangeService and the IReferenceService interfaces.

C#
protected void UpdateDataBindings() 
{
  // create a new collection to store the new bindings found
  DataBindingInfoCollection newBindings = new DataBindingInfoCollection();

  // gets all web controls from the form
  IReferenceService service = (IReferenceService)GetService(
    typeof(IReferenceService));
  object[] references = service.GetReferences(typeof(Control));

  foreach(Control control in references){
    // if the control isn't in the page but it's a naming container, skip it
    if ((control.NamingContainer == null) || 
       (control.NamingContainer.GetType() != typeof(Page))) continue;
    
    // get the interface related to data binding
    IDataBindingsAccessor dba = (IDataBindingsAccessor)control;

    if (dba.HasDataBindings){
      foreach (DataBinding db in dba.DataBindings){
        // get the binding information for the control
        DataBindingInfo dbi = GetBindingInformation(db, control);

        // if the entry isn't new, set the old values
        UpdateDataBindingInfo(dbi, bindingManager.DataBindings);

        newBindings.Add(dbi);
      }
    }
  }

  // if the data bindings have changed
  if (CheckBindingChanges(bindingManager.DataBindings, newBindings)){
    // notify that the component is going to change
    RaiseComponentChanging(null);

    // update the bindings
    bindingManager.DataBindings.Clear();
    foreach(DataBindingInfo dbi in newBindings){
      bindingManager.DataBindings.Add(dbi);
    }

    // notify that the component has changed
    RaiseComponentChanged(null, null, null);
  }
}

We need to make available the data binding information to our WebForm in run time so we serialize that information to code thanks to a custom TypeConverter.

The class diagram is:

Image 2

The actual data binding is implemented in two methods in our BindingManager: BindToWebForm and BindFromWebForm. BindToWebForm is easy to implement, because it uses the DataBinding architecture of ASP.NET so we have nearly all the work done. BindFromWebForm is more complex, because it has to iterate through the data bindings, and for each databinding, get the control's property type and compare it with the destination property. If they match, then it can perform the data binding. If not, it tries to convert from the source property type to the destination type before assigning the data. This conversion can be done successfully if the destination type has a TypeConverter that does the job or if it has a static method called Parse.

C#
public void BindFromWebForm(Page form) 
{
  // iterate through the data bindings
  foreach (DataBindingInfo dbi in _dbic){
    // if the binding isn't two way, exit
    if (!dbi.TwoWay) continue;

    // get property to bind from
    object sourceProp = GetFieldOrPropertyEx(dbi.Control, dbi.PropControl);
    
    // if we can't get the property, error
    if (sourceProp == null) throw new DataBindingException(
        "DataBinding error, can't find: " + dbi.PropControl, dbi.Control);
    
    // get the full property name
    string fullPropObject = dbi.Object;
    if (dbi.PropObject != null){
      fullPropObject += "." + dbi.PropObject;
    }

    // check source and destination types
    Type sourcePropType = sourceProp.GetType();
    Type destPropType = GetFieldOrPropertyTypeEx(form, fullPropObject);

    if (destPropType == null){
      throw new DataBindingException(
        "DataBinding error, can't find: " + fullPropObject, dbi.Control);
    }

    // if the types doesn't match try to make a conversion
    if (!sourcePropType.Equals(destPropType)){
      try {
        sourceProp = ConvertTypes(sourceProp, destPropType);
      } catch (Exception e){
        throw new DataBindingException(
          "DataBinding error, can't convert types: ", e, dbi.Control);
      }

      if (sourceProp == null){
        throw new DataBindingException(
         "DataBinding error, can't convert bound property: " + 
          dbi.PropControl + " for: " + fullPropObject, dbi.Control);
      }
    }
    
    // do the data binding
    if (!SetFieldOrPropertyEx(form, fullPropObject, sourceProp)){
      throw new DataBindingException("DataBinding error, can't set: " 
           + fullPropObject, dbi.Control);
    }
  }
}

Notes

The actual implementation has some limitations:
  • When the BindingManager parses the data bindings through the IDataBindingAccessor interface it doesn't expect a complex data binding expression. For example: If you want to bind the full name of a customer to a label with something like <%# DataBinder.Eval(customer1, "Name") + " " + DataBinder.Eval(customer1, "Surname") %> it will fail. You can do the same with a panel and two labels, each one with a simple data binding expression (Label1 with: <%# DataBinder.Eval(customer1, "Name") %> and Label2 with <%# DataBinder.Eval(customer1, "Surname")) %>
  • By design, if the bound controls are inside a NamingContainer (for example, if you have a template column in a DataGrid), they don't get added to the binding collection of the BindingManager, because controls like the DataGrid aren't designed to support two way databinding. You can change this behaviour if you want

History

  • v1.0. Initial Release.
  • v1.1. Added support for int and string indexers and better type conversion.

Last comments

This is my first article and I don't have a lot of free time to write articles, so if you have enjoyed this one, please rate it and it will encourage me to write more.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Spain Spain
Manuel Abadia had his MS Degree in Computer Science (Univ. Murcia, Spain)

He is a Freelance Software Architect/Engineer and Trainer.

He sells his own components in his webpage (http://www.manuelabadia.com).

He was the Software Architect for the MoviTAP project that won the first prize in the Microsoft and Vodafone mobile web Services contest.

He has done some external work in companies like Namco America Inc. and Gaelco SA.

He has contributed to the MAME project (http://www.mamedev.com) for some years (and continues to do so eventually).

Comments and Discussions

 
GeneralBindingManager and .net 2.0 / VS2005 Pin
sdess18-Apr-07 4:28
sdess18-Apr-07 4:28 
GeneralRe: BindingManager and .net 2.0 / VS2005 Pin
Manuel Abadia23-Apr-07 4:04
Manuel Abadia23-Apr-07 4:04 
QuestionWhat about ListControls? Pin
sheir3-Feb-06 5:46
sheir3-Feb-06 5:46 
QuestionHow to add to toolbox in VS2005? Pin
sheir1-Feb-06 9:27
sheir1-Feb-06 9:27 
AnswerRe: How to add to toolbox in VS2005? Pin
Manuel Abadia2-Feb-06 1:14
Manuel Abadia2-Feb-06 1:14 
AnswerRe: How to add to toolbox in VS2005? Pin
Simone Busoli25-Mar-06 13:28
Simone Busoli25-Mar-06 13:28 
GeneralRe: How to add to toolbox in VS2005? Pin
Member 9628-Jul-06 5:43
Member 9628-Jul-06 5:43 
GeneralRe: How to add to toolbox in VS2005? Pin
Simone Busoli28-Jul-06 7:16
Simone Busoli28-Jul-06 7:16 
GeneralRe: How to add to toolbox in VS2005? Pin
Edbert P6-Mar-07 17:26
Edbert P6-Mar-07 17:26 
GeneralRe: How to add to toolbox in VS2005? Pin
fgarcia1-Jul-10 6:19
fgarcia1-Jul-10 6:19 
GeneralRe: How to add to toolbox in VS2005? Pin
gavb12316-Jun-08 21:14
gavb12316-Jun-08 21:14 
Questionusing it in a web user control? Pin
z_free2-Oct-05 6:59
z_free2-Oct-05 6:59 
AnswerRe: using it in a web user control? Pin
chengbiny23-Nov-05 5:27
chengbiny23-Nov-05 5:27 
GeneralNamingContainer Pin
EricSch3-May-05 6:19
sussEricSch3-May-05 6:19 
GeneralMultiple objects that are the same type Pin
99024688-Apr-05 4:57
99024688-Apr-05 4:57 
GeneralAnother Method Pin
johndyer15-Feb-05 3:24
johndyer15-Feb-05 3:24 
GeneralBindingManager and DataGrid Pin
oaam4-Nov-04 6:03
oaam4-Nov-04 6:03 
GeneralSorry... Pin
Manuel Abadia25-Oct-04 23:05
Manuel Abadia25-Oct-04 23:05 
GeneralRe: Sorry... Pin
inetmaster29-Oct-04 10:38
inetmaster29-Oct-04 10:38 
GeneralHaving Trouble Pin
inetmaster23-Oct-04 2:29
inetmaster23-Oct-04 2:29 
GeneralCOOL ! but...... Pin
Gary_Wenneker5-Oct-04 2:36
Gary_Wenneker5-Oct-04 2:36 
GeneralIndexer and custom datasets Pin
SAO20037-Sep-04 4:14
SAO20037-Sep-04 4:14 
GeneralRe: Indexer and custom datasets Pin
SAO20038-Sep-04 1:32
SAO20038-Sep-04 1:32 
GeneralRe: Indexer and custom datasets Pin
SAO20038-Sep-04 4:23
SAO20038-Sep-04 4:23 
GeneralRe: Indexer and custom datasets Pin
SAO200315-Sep-04 3:07
SAO200315-Sep-04 3:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.