Nov 20, 2008

Cannot have multiple items selected in a DropDownList. Why is this ASP.NET / C# exception rised?

This is a common exception. It happens when you do something like:

        
ListItem li1 = new ListItem();
        li1.Text =
"Item 1";
        li1.Value =
"id1";
        li1.Selected =
true;
        
ListItem li2 = new ListItem();
        li2.Text =
"Item 2";
        li2.Value =
"id2";
        li2.Selected =
true;
        ddTest.Items.Add(li1);
        ddTest.Items.Add(li2);

Let's explain what is going on.
We created a ListItem, set its name and value and make it to be selected.
Then we created another ListItem, again set its value and name and set it to be selected.


When we add both ListItems the DropDownList confuses about which one should be selected and throws an exception. But why?
Because there is another control - ListBox, which allows multiple selection. If we create a ListBox on the form and add the following code in the code behind:


        
ListItem li1 = new ListItem();
        li1.Text =
"Item 1";
        li1.Value =
"id1";
        li1.Selected =
true;

        
ListItem li2 = new ListItem();
        li2.Text =
"Item 2";
        li2.Value =
"id2";
        li2.Selected =
true;

        lb1.SelectionMode =
ListSelectionMode.Multiple;
        lb1.Items.Add(li1);
        lb1.Items.Add(li2);

We will run with no errors and both items will be selected. The problem with the DropDownList control is that shares almost the same functionality with the ListBox and for that reason they both inherit the same base objects.

But the DropDownList doesn't have the ability to display multiple items so ASP.NET team decided to throw an exception when such situation occurs.




This can be confusing in more complicated code, but it is definatelly better than selecting the last item which was marked as "selected" or the first one or something like that.
Luckily there are safer ways to select an item without having to worry if there is already selected item or not.

You can use DropdownList.SelectedIndex or DropdownList.SelectedValue properties to mark selected item in a safe manner. So if in the firs example we wanted to select the item with id2 we can use the following code:

        
ListItem li1 = new ListItem();
        li1.Text =
"Item 1";
        li1.Value =
"id1";

        
ListItem li2 = new ListItem();
        li2.Text =
"Item 2";
        li2.Value =
"id2";

        ddTest.Items.Add(li1);
        ddTest.Items.Add(li2);

        ddTest.SelectedValue =
"id2";

I commonly use this as in most cases I know which value should I select but don't know which index it has.
Now, there is a situation in which you may want to select by index and this in my imagination is the following situation:
Imagine you have the above DropDownList but you want it to be optional. This means that you need to have an item with empty value or value that means "null" to you. Imagine that this value is already inserted in the DropDownList. You know it will always be the first item. Here is the snippet:

        
ListItem liNull = new ListItem();
        liNull.Text =
"-- Please Select an Item --";
        liNull.Value =
"";

        
ListItem li1 = new ListItem();
        li1.Text =
"Item 1";
        li1.Value =
"id1";

        
ListItem li2 = new ListItem();
        li2.Text =
"Item 2";
        li2.Value =
"id2";

        
// Someone selected item in the code:
        ddTest.SelectedValue = "id1";

        ddTest.Items.Add(liNull);
        ddTest.Items.Add(li1);
        ddTest.Items.Add(li2);

        
// We will select the first one which is "-- Please Select an Item --"
        ddTest.SelectedIndex = 0;

But in such cases we can take advantage of the default DropDownList behaviour (the DropDownList will select the first item if there are no items selected explicitly). So if you need the first item selected you can simply clear the selection and ASP.NET will select it for you. But how?
By using the ClearSelection() method. It does what it says - it clears the selected item.
Here is the last snippet:

        
ListItem liNull = new ListItem();
        liNull.Text =
"-- Please Select an Item --";
        liNull.Value =
"";

        
ListItem li1 = new ListItem();
        li1.Text =
"Item 1";
        li1.Value =
"id1";

        
ListItem li2 = new ListItem();
        li2.Text =
"Item 2";
        li2.Value =
"id2";

        
// Someone selected item in the code:
        ddTest.SelectedValue = "id1";

        ddTest.Items.Add(liNull);
        ddTest.Items.Add(li1);
        ddTest.Items.Add(li2);

        
// We will be sure that everything is clean
        // and will expect ASP.NET to select the first item
        // by default:
        ddTest.ClearSelection();

No comments: