Sunday, October 12, 2008

Code Nuggets: A Side-effect of Using DropDownList AppendDataBoundItems With DataBound Items

Picture this: You have a webform with two DropDownLists, both of them are databound to some data you get from a database. Now the first DropDownList's selection determines the contents of the second dropdown. So you simply do a AutoPostBack = true for the first dropdown and populate the second dropdown in the handler function. Right?

But wait. What if you are required to put in a static item in the dropdown? Something like "-- Please Select --" as the first item in the list to force the user to make a conscious choice. Hmmm, so you look around and find the nice little property named AppendDataBoundItems that will take care of that. All you have to do is declare the first (static) item in the Items collection in the designer (or put a <asp:ListItem> tag inside your <asp:DropDownList> tags) and set AppendDataBoundItems to true. This nice little property tells the DropDownList to add the databound items after the statically declared items, so you can have your happy little "-- Please Select --" in your dropdown.

The Side-effect:

The side-effect becomes evident when you play around with your two dropdowns. Its immediately clear that something is not quite right. The AppendDataBoundItems property forces your dropdown's items from the previous postback to be treated as static objects on this display. Sort of where you get an ever-growing second dropdown with a hangover from the postback, which is clearly not what you wanted in the first place!

The Nugget:

So the quick solution is to use a loop to remove items selectively from your dropdown. Remember you still want to retain your first item, so that's why you use a loop. And a while loop at that.

while (DropDownList1.Items.Count != 1)
{
    DropDownList1.Items.Remove(DropDownList1.Items[1]);
}

There. You won't have a problem with your static-dynamic dropdowns anymore! You can even extend it to other purposes, if you have several static items that you want to preserve, or if you want to preserve static items that are of a particular value. The possibilities are endless, and the pain in your back is gone.

Other Possible Solutions Others Propose:

Some people think that doing a DropDownList1.Items.Clear() would do the trick, but it doesn't. Remember, you want to retain your first object. Or if you want to add your first (static!) object manually again then perhaps you can do that.

Yet others propose a rather swashbuckling DropDownList1.EnableViewState = false, do this only at your own risk and if you are sure that your user would never have to land on this page again during the current flow of your application (of course for which you cannot be sure, what if there is a network timeout?).

A Note:

Perhaps you'd want to use a for loop in place of that while loop, trying to do a quick

for (int i = 0; i < DropDownList1.Items.Count; i++)
{
    DropDownList1.Items.RemoveAt(i);
}

but believe me, it wouldn't work. Why? Because the DropDownList shrinks as you remove items from it, so your loop is bound to fail at some point, terminating earlier than it should. And of course I don't have to remind anyone that you cannot remove items from a collection while using an Iterator.

So that's it, I think the nugget had pretty much sauce alongside it!

(You can get a low-down on AppendDataBoundItems on ScottGu's blog or Andrew Rea's blog)