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.