ASP.Net Data Binding Patterns

One of the things we've found at work is that the code to bind your data to your page can quickly get out of control if you don't pay attention.  Things get worse with ASP.Net 2.0 as we introduce master pages and another place to control our data.  In this post I will outline what I have found to be the easiest guidelines for predictable and controllable data binding.

I assume you are already familiar with the basic data binding concepts and are trying to use them in a larger application.  If these concepts are new to you I suggest you spend some time at the official ASP.Net site which has a number of good tutorials.

Readability

The first issue we want to address is readability.  We should be able to easily understand when a control will be data bound and there should not be any guesswork involved in either developing or reading the data binding code.  This will help us develop quickly and avoid too much confusion when we have to make changes later.

Timing

Timing data binding correctly is a critical part of making it work.  We need to make sure data binding happens at the right point in the page lifecycle so that all of our dependencies are in place.  Sometimes we will need to delay binding of some controls until other parts of the page are ready.

Efficiency

We often fetch data from a database when we bind so giving some thought to efficiency is important to keep our web applications performing well.  We want to avoid binding controls more than once or binding things unnecessarily. 

DataBind()

All pages, controls and master pages derive from the Control class which provides a DataBind() method.  We will override this method to bind my data and to control how related controls are bound.  To keep things nice and simple the DataBind() method is going to be the one and only way to trigger data binding.

Binds a data source to the invoked server control and all its child controls.
MSDN

A lot happens inside a typical DataBind() call but the two things that are most important to us are mentioned in the description above.  First if the control supports data binding it will be bound to the data currently set in its DataSource property.  Secondly the control will call DataBind() recursively on all of it's child controls.

The reason this is so important is that it tells us the explicit order in which things will happen.  Data binding will works its way down the control tree from where we start until it reaches the bottom.  Parent controls will always be bound before their children and child controls will always be bound after the control that contains them.  The simplified control tree for a typical ASP.Net page might look like this:

  • Page (.aspx)
    • Master Page (.master)
      • Content Placeholder
        • Heading
        • User Control (.ascx)
          • Label
          • Drop Down List
          • Validator
        • Text Box
        • Footer

The most important thing that people don't realise is that the master page is a child of the page.  This means when we call DataBind() the page will be found first, followed by the master page and then any controls contained in the content placeholders on the page.  Keep this in mind if you are relying on the master page to set up any data for other controls.

Overriding DataBind()

By overriding DataBind() we gain control over the flow of data.  There are two important tasks to perform in override, setting up and data we are responsible and calling DataBind() on our children.

public override void DataBind()

{

    // Set up data

    dropDownList.DataSource = GetSomeData();

    repeater.DataSource = GetMoreData();

    textBox.Text = "Hello!";

 

    // Bind our children implicitly

    base.DataBind();

}

By calling the base classes Databind() method at the end of the function we are implicitly calling DataBind() on both the drop down list and the repeater we have already set up with data sources.  We do not need to call their DataBind() methods directly.

There are times when we have controls on the page that we don't want bound.  This might be because they are hidden or inactive for the moment.  When we want to do this we can remove the call to the base DataBind() and instead bind only the controls we want.

public override void DataBind()

{

    // Set up data and bind explicitly

    dropDownList.DataSource = GetSomeData();

    dropDownList.DataBind();

 

    repeater.DataSource = GetMoreData();

    repeater.DataBind();

 

    textBox.Text = "Hello!";

 

    userControl.DataBind();

}

If you use the second method you must remember to call DataBind() on all of your children that need it.  For example if you have a user control on the page you may need to bind it so that it can bind its children in turn even though it does not have a DataSource property.

Calling DataBind()

With the data binding infrastructure in place there is one important question we still haven't answered, where should we start the whole data binding process?  Fortunately the answer is usually quite simple, in each page class.  There are a couple of reasons this is the best place to call it from.  Firstly the page is the root of the control tree which means we only need to call DataBind() a single time to set up our whole page.  Secondly pages tend to differ greatly in their structure and workflow so calling DataBind() in the page will cater to more scenarios than if we called it in the master page or elsewhere.

public partial class WebForm1 : Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        if (IsPostBack)

            return;

 

        DataBind();

    }

 

    protected void Button1_Click(object sender, EventArgs e)

    {

        DoWork();

 

        DataBind();

    }

If the request is a post back we skip the data binding.  On a post back we normally have another event that is going to fire after the Page_Load and make some modifications to the page.  We will leave it up to that event to call DataBind() so that we do not overwrite the values the user posted us and so that we do not end up binding twice.

The only quirk with performing data binding at the end of Page_Load is that it happens before the Page_Load event of any user controls on the page.  I normally design my user controls so that this is not a problem but you can move the data binding to a later stage such as OnPreRender() if necessary.

post.DataBind().

Labels: , ,

16/04/2008 03:47 AM (UTC -07:00)