开发者

ASP.NET Web Forms DropDownList has a SelectedValue which is invalid because it does not exist in the list of items

开发者 https://www.devze.com 2023-03-03 00:44 出处:网络
First of all there has been questions ( DropDownList has a SelectedValue which is invalid because it does not exist in the list of items , DropDownList "has a SelectedValue which is invalid becau

First of all there has been questions ( DropDownList has a SelectedValue which is invalid because it does not exist in the list of items , DropDownList "has a SelectedValue which is invalid because it does not exist in the list of items" , asp:DropDownList Error: 'DropDownList1' has a SelectedValue which is invalid because it does not exist in the list of items ) about this and there are proposed workarounds but my question is really WHY this happens. What is more I am not satisfied with the suggested workarounds and I find them quite ugly.

So there is a page with a drop down list and a button:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="TestWebApplication.WebForm2" ViewStateMode="Disabled" %>

<html lang="en" >
<body>
    <form id="form1" runat="server">
    <div>
        <asp:DropDownList ID="ddlTest" runat="server">
        </asp:DropDownList>
        <asp:Button Text="Test" ID="btnTest" runat="server" onclick="btnTest_Click" />
    </div>
    </form>
</body>
</html>

I bind ddlTest with some items on Page_Init and then in btnTest_Click I bind again:

using System;

namespace TestWebApplication
{
    public partial class WebForm2 : System.Web.UI.Page
    {
        protected void Page_Init(object sender,开发者_StackOverflow中文版 EventArgs e)
        {
            //SelectedIndex is -1, SelectedValue is "", SelectedItem is null
            ddlTest.DataSource = new[] { 1, 2, 3 };
            ddlTest.DataBind();
            ddlTest.SelectedValue = "3";
        }

        protected void btnTest_Click(object sender, EventArgs e)
        {
            //SelectedIndex is 2, SelectedValue is "3", SelectedItem is {3}
            ddlTest.ClearSelection();
            //SelectedIndex is 0, SelectedValue is "1", SelectedItem is {1}
            ddlTest.SelectedIndex = -1; //Nothing changes including SelectedIndex
            ddlTest.SelectedValue = ""; //Nothing changes including SelectedValue
            ddlTest.Items.Clear();
            //SelectedIndex is -1, SelectedValue is "", SelectedItem is null
            ddlTest.DataSource = null; //Nothing changes except for the DataSource property
            ddlTest.DataSource = new[] { 1, 2 };
            ddlTest.DataBind();//Exception!
            //'ddlTest' has a SelectedValue which is invalid because it does not exist in the list of items.
            //Parameter name: value
        }
    }
}

Why do I get the exception. I tried different versions of these and none of them works. I tried using only ClearSelection but still got the same exception. Is this bug in the control or something I miss. Are the ugly workarounds from the other questions the only solution?

Note - the bug is reproduceable even if the button is removed and the all the code is moved in a single event handler. Just bind once set selected value and bind again.


I've submitted a bug on Connect for the issue. It was resolved as "Won't fix" which in my mind means it is in fact a bug. A workaround was provided:

ddlTest.Items.Clear();
ddlTest.SelectedValue = null;

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

I kind of consider this the answer.


Why do I get the exception.

After Page_Init() is called, ddlTest has been bound to 3 items: "1", "2" and "3". You then set the SelectedValue to "3" and manipulate all sorts of things related to the DropDownList control. But the control is still bound to the previous list -- you haven't called .DataBind() again even though you've changed the DropDownList properties. The exception occurs because the control is still bound to the {1, 2, 3}, it's hanging on to the previous .SelectedValue and you've just tried to .DataBind() it to a list that does not include "3".


I had a similar problem and fixed it by adding a DataBinding method.

protected void myDDL_DataBinding(object sender, EventArgs e)
{
    if (myDDL.SelectedIndex != -1)
    {
        myDDL.SelectedIndex = 0;
    }
}

On design page...

<asp:DropDownList ID="myDDL" runat="server" 
    AutoPostBack="true" OnDataBinding="myDDL_DataBinding"
    OnSelectedIndexChanged="myDDL_SelectedIndexChanged">
</asp:DropDownList>


1) As written, your example actually throws an exception on ddlTest.SelectedValue = "";, since there is no item in the collection with a Value of "". I think this would be expected under any circumstance.

2) I get an exception every time I try to set the SelectedValue or SelectedIndex of the DDL to something that WILL BE invalid by the time the DDL is rendered. But the exception doesn't happen until the DropDownList.Items collection is actually changed, for instance with a DropDownList.Databind(). The first thing I did was make this change to Page_Init:

protected void Page_Init(object sender, EventArgs e)
{
    //SelectedIndex is -1, SelectedValue is "", SelectedItem is null
    if (!IsPostBack)
    {
        ddlTest.DataSource = new[] { 1, 2, 3 };
        ddlTest.DataBind();
        ddlTest.SelectedValue = "3";
    }
}

Now what gets interesting is this first example throws an exception, but the second one doesn't. They both set a SelectedValue that is valid at the time, but the value in the first example ("3") will not be valid by the time the page renders:

protected void btnTest_Click(object sender, EventArgs e)
{
    //SelectedIndex is 2, SelectedValue is "3", SelectedItem is {3}
    ddlTest.SelectedValue = "3"; 
    //SelectedIndex is 2, SelectedValue is "3", SelectedItem is {3}
    ddlTest.ClearSelection();
    //SelectedIndex is 0, SelectedValue is "1", SelectedItem is {1}
    ddlTest.Items.Clear();
    //SelectedIndex is -1, SelectedValue is "", SelectedItem is null
    ddlTest.DataSource = null;
    ddlTest.DataSource = new[] { 1, 2 };
    ddlTest.DataBind(); //Exception!
    //'ddlTest' has a SelectedValue which is invalid because it does not exist in the list of items.
    //Parameter name: value
}

protected void btnTest_Click(object sender, EventArgs e)
{
    //SelectedIndex is 2, SelectedValue is "3", SelectedItem is {3} (from viewstate)
    ddlTest.SelectedValue = "2"; 
    //SelectedIndex is 1, SelectedValue is "2", SelectedItem is {3}
    ddlTest.ClearSelection();
    //SelectedIndex is 0, SelectedValue is "1", SelectedItem is {1}
    ddlTest.Items.Clear();
    //SelectedIndex is -1, SelectedValue is "", SelectedItem is null
    ddlTest.DataSource = null;
    ddlTest.DataSource = new[] { 1, 2 };
    ddlTest.DataBind(); //No Exception...
}

So, what conclusion can we draw from this? Well it seems the problem is due to setting the SelectedIndex or SelectedValue property of the DDL before the contents of the DDL may be changed on the same page cycle. If the previously set value is still available in the new contents of DropDownList.Items, you're in business. But if it's not in there, you get an exception.

My guess is this has something to do with thread-safeness but I'm no expert on that so hopefully someone can comment.


In my case I had DropdownList in templatedfield of gridview. Now datasource of grid had employeeid item. I have this in stored proceedure, isnull(employeeid,0) for datasource and guess what DropdownListdoes not have a value of 0 on its items; so i changed that to isnull(employeeid,1) because the first item in DropdownListhas employeeid =1 and this solved problem


Because there is no any datasource when your page is reloaded (postback happened), you should add SqlDataSource control in your .aspx file even in reloading page recognize DropDownList's DataSource. Then You can use InsertCommand, UpdateCommand, DeleteCommand and SelecCommand to obtain your DB.

0

精彩评论

暂无评论...
验证码 换一张
取 消