Tuesday, April 07, 2009

'DropDownList' has a SelectedValue which is invalid because it does not exist in the list of items.

This error occurs when the SelectedValue property of a DropDownList is being set to a value which does not exist in the DropDownList. There are various reasons this can occur. In my case, the cause was that a record in the database was referring to a user configurable "category" that had been deleted by the user. Here are three possibilities for handling the scenario. They differ mostly in style, so pick the one that suits your taste.

All of these examples use a DropDownList set up like this:

<asp:DropDownList runat="server" ID="ddlCategory" DataSource='<%# GetCategories() %>'   
    DataTextField="Value" DataValueField="Key" AppendDataBoundItems="true">
    <asp:ListItem Text="(none)" Value="" />
</asp:DropDownList>

Option 1:



SelectedIndex='<%# Eval("CategoryID") is DBNull ? -1 : ddlCategory.Items.IndexOf(ddlCategory.Items.FindByValue(Eval("CategoryID").ToString()))  %>'



Here, I use the ternary operator to determine the index to select. If the database value is DBNull then -1 is used as the index, otherwise a search of the existing list items is performed to determine where in the list the desired value is. The great thing about this is that if the item is not DBNull but it's not in the list of items either, IndexOf() will return -1!

Option 2:



SelectedIndex='<%# GetSelectedCategoryIndex(ddlCategory, Eval("CategoryID")) %>'



This passes the DropDownList and the desired value to a method. There you can use the provided information to determine which index to use and handle any errors that may occur. The method should return an int value.

Option 3:


aspx:

OnDataBound=ddlCategory_DataBound



C#:
protected void ddlCategory_DataBound(object sender, EventArgs e)
{
    ddlCategory = sender as DropDownList;
    //set the selected index.  If the CategoryID is not in the list, set index to 0
    ddlCategory.SelectedIndex = 0;
    try
    {
        ddlCategory.SelectedValue = ((GetDataItem() as DataRowView).Row["CategoryID"]).ToString();
    }
    catch { }
}

7 comments:

  1. Good post. Thanks for the info!

    ReplyDelete
  2. The last method doesn't seem to work, since the ArgumentOutOfRangeException gets thrown before the DataBound event fires. I'm using an ObjectDataSource for the data binding.

    ReplyDelete
  3. Hi, is not working.. where do I need to put the selectindex..
    Compiler Error Message: BC30108: 'DBNull' is a type and cannot be used as an expression.

    SelectedIndex='<%# Eval("CategoryID") is DBNull ? -1 : ddlCategory.Items.IndexOf(ddlCategory.Items.FindByValue(Eval("CategoryID").ToString())) %>'

    ReplyDelete
  4. SelectedIndex is a property of the DropDownList control.

    <asp:DropDownList runat="server" ID="ddlCategory"
    SelectedIndex=...>

    ReplyDelete
  5. Thanks for this. Been searching for a solution all morning.

    I used the last method but placed

    ddlCategory.SelectedIndex = 0;

    within the try{
    }

    ReplyDelete
  6. Semi-related: I was getting this error because in my EditItemTemplate I was binding to a DropDownList where one of my DataValues was a decimal, ".5". When I tried to update a row with this value, it said the item didnt exist in my list, which I knew it was. Turns out it wasn't finding it because the ListItem Value was ".5" - I had to change it to "0.5" and then it worked fine.

    ReplyDelete
  7. This link may help someone,
    https://connect.microsoft.com/VisualStudio/feedback/details/666808/asp-net-dropdownlist-selectedvalue-is-persisted-which-results-in-exception-if-the-control-is-databound-second-time

    ReplyDelete