Building a Composite Databound Control the 2.0 Way
Posted in Development
ASP.NET 2.0 shipped with a new server control, CompositeDataBoundControl, which considerably cuts down on the amount of code you have to write by hand. Since its documentation is a little out of whack, I decided to point out a couple of things.
The old way
Back in them ol’ dark days of ASP.NET 1.x, you had to write quite a lot of plumbing code to build a databound server control. Scott Mitchell has a thorough article, Building DataBound Templated Custom ASP.NET Server Controls, which explains this process inside out. The technique is also covered at great lengths in Nikhil’s book.
The new way
CompositeDataBoundControl alleviates some of the pain by implementing boring plumbing. In a fairly simple control all you have to do is override CreateChildControls, as the sample code at MSDN demonstrates.
I believe one thing it misses is that you need to pay attention to the dataBinding parameter. It is true when you call DataBind() and false when the control is being rebuilt from view state on postback. Therefore the while (e.MoveNext()) { ... } loop needs to populate a row only when dataBinding is true.
I put together a sample control that builds a list of books in an unordered list (<ul>). The calling code sets the control’s DataSource property to a list of books and calls DataBind(). In this scenario, CreateChildControls will hold this book list in its dataSource parameter, and dataBinding is true.
It is important to return the correct number of items you added as it’s stored in view state, as Reflector reveals:
protected internal override void PerformDataBinding (IEnumerable data) { … int num1 = this.CreateChildControls(data, true); base.ChildControlsCreated = true; this.ViewState["_!ItemCount"] = num1; }
On postback, the familiar paremeterless CreateChildControls() kicks off another round of binding, this time with a fake data data source and dataBinding set to false:
protected internal override void CreateChildControls() { this.Controls.Clear(); object obj1 = this.ViewState["_!ItemCount"]; … object[] objArray1 = new object[(int) obj1]; this.CreateChildControls(objArray1, false); base.ClearChildViewState(); }
Order of control population matters
Here’s a bit of view state trivia. What’s the difference between the following code snippets:
// Original if (dataSource != null) { CheckBoxList bookList = new CheckBoxList (); Controls.Add (bookList); IEnumerator e = dataSource.GetEnumerator (); while (e.MoveNext ()) { … } } // Modified if (dataSource != null) { CheckBoxList bookList = new CheckBoxList (); IEnumerator e = dataSource.GetEnumerator (); while (e.MoveNext ()) { … } Controls.Add (bookList); }
Basically, the second sample adds the fully populated book list at the end, once looping is done.
The difference is huge
The second sample will lose list items on postback because there’s nothing for them in view state so they can’t be rebuilt.
Again, Nikhil explained the “why” is his book (“View Sate and Child Controls”, page 310). You can also read Scott’s explanation of this nuance. When you come back, it should be clear why Controls.Add (bookList) appears at the top.
4 comments
Milan Negovan
on October 5, 2008
I'd be curious to know if this reversal is a Mono issue. My sample code came from a real-world app (it wasn't books, but still) and I know it worked.
If you find something, please share. :)
Raj Kiran Singh
on June 3, 2009
What If I do not want to persist data in view state.
I am developing a templated drop down box control and want to give user an option to reduce view state, but for that user would have to bind datasource each time the page postbacks.
Now I am facing an issue with second calling of createchildcontrols method, the control keeps old data and adds new one, which result in duplicate ids.
Can you throw some light what might be the issue here.
Milan Negovan
on June 3, 2009
Yes, you would need to re-bind the control on the first load as well as subsequent postbacks.
Note: if you utilize autopostbacks from the dropdown picker, you are stuck with view state.
Without seeing your code I'm not sure why CreateChildControls is called twice. Theoretically, it shouldn't happen.

Smv
on October 5, 2008
Hi, first of all thank you for the nice post. I know it's very old but since I found it useful and (maybe) discovered a problem in it, I'd like to point it out.
I've played a little with your sample code (running on Mono) ad noticed that the same problem described in 'Order of control population matters' is present inside the while loop:
while (e.MoveNext ())
{
ListItem bookItem = new ListItem ();
/* If the control is rebuilding itself with data from
* view state, dataBinding is false and dataSource contains an array
* of null elements. */
if (dataBinding)
{
Book book = (Book) e.Current;
bookItem.Text = string.Format ("{0}: {1:C}", book.Title, book.Price);
}
bookList.Items.Add (bookItem);
itemCount++;
}
Should be:
while (e.MoveNext ())
{
ListItem bookItem = new ListItem ();
// Add bookItem BEFORE changing its properties.
bookList.Items.Add (bookItem);
/* If the control is rebuilding itself with data from
* view state, dataBinding is false and dataSource contains an array
* of null elements. */
if (dataBinding)
{
Book book = (Book) e.Current;
bookItem.Text = string.Format ("{0}: {1:C}", book.Title, book.Price);
}
itemCount++;
}
Otherwise the first bookItem properties are not preserverd in the ViewState.
You will notice this at the second PostBack of the page.
Maybe it's just a Mono problem, I haven't tried with MS .NET yet.
Bye