DataBinding asp.net DropDownList from a List of ListItems causing System.ArgumentOutOfRangeException Error

2.5k Views Asked by At

I am attempting to DataBind an asp:DropDownList with a Collections.Generic.List of System.Web.UI.WebControls.ListItems. The DataBind() is throwing this error.

System.ArgumentOutOfRangeException: 'ddlPlatinumOptions' has a SelectedValue which is invalid because it does not exist in the list of items.

.ascx

<asp:DropDownList ID="ddlPlatinumOptions" runat="server" AutoPostBack="true" width="100%"></asp:DropDownList>

.ascx.cs

public void BindPlatinumOptions()
{
    ddlPlatinumOptions.DataTextField = "Text";
    ddlPlatinumOptions.DataValueField = "Value";
    ddlPlatinumOptions.DataSource = _platinumOptions;
    ddlPlatinumOptions.DataBind(); // Throwing Error
}

presenter

MattressProtectionInfo standard = RF_ProtectionPlan.GetMattressPlanInfo(MattressId, false);
MattressProtectionInfo premium = RF_ProtectionPlan.GetMattressPlanInfo(MattressId, true);
List<ListItem> plans = new List<ListItem>();                  
if (standard != null)
{
    plans.Add(new ListItem(standard.Price.ToString("C") + " - Standard 5-Year Platinum Protection", standard.ProductID.ToString()));
}
if (premium != null)
{
    plans.Add(new ListItem(premium.Price.ToString("C") + " - Premium 5-Year Platinum Protection", premium.ProductID.ToString()));
}

_view.PlatinumOptions = plans;
_view.BindPlatinumOptions();

Data Example

  • Value = "21696" Text = "$99.95 - Standard 5-Year Platinum Protection"
  • Value = "21702" Text = "$119.95 - Premium 5-Year Platinum Protection"

Thing I have tried

  • Nulling datasource and Databinding before my data to clear out anything (broke on dataBind as well)
  • relocating position of DataTextField and DataValueField (waste of time - no change)
  • declaring a selected index of 0 before the databind
  • ddlPlatinumOptions.Items.Clear();
  • ddlPlatinumOptions.ClearSelection();

I am grabbing at straws. It appears as if the databind is trying to select something inside of the dropdownlist that isn't there.

Is there an error in my code I'm not seeing? Any Ideas?

2

There are 2 best solutions below

1
On BEST ANSWER

Well, it's an out of range exception.. Are you setting the SelectedIndex to a default value at any point before you are binding to the DropDownList?

0
On

After facing this problem, too, I debugged the ASP.NET source code and found a flaw(?) in the ASP.NET source code (and, hence, the solution to our problem):

Internally, System.Web.UI.WebControls.Listcontrol caches the most recently used SelectedValue. So when a data binding occurs (which natively clears the SelectedValue property) after the SelectedValue has already been set from Request.Form[], the data binding operation tries to find and pre-select the previously cached item. Unfortunately it throws an exception when the cached value isn't found in the new DataSource list instead of silently leaving the current SelectedValue null value alone.

I guess they did that because when using ViewState and data source objects for data binding, the later data bind operation would remove the SelectedValue obtained by Request.Form[].

So, whenever you perform more than one data binding operation on a ListControl within a page lifecycle and when the data sources differ, then this exception occurs.


Here's the ASP.NET code synopsis:

    public virtual string SelectedValue
    {
        set
        {
            if (Items.Count != 0)
            {
                // at design time, a binding on SelectedValue will be reset to the default value on OnComponentChanged
                if (value == null || (DesignMode && value.Length == 0))
                {
                    ClearSelection();
                    return;
                    // !!! cachedSelectedValue is not getting reset here !!!
                }

            ...

            // always save the selectedvalue
            // for later databinding in case we have viewstate items or static items
            cachedSelectedValue = value;
        }
    }


And here's the solution:

Instead of:

    dropDownBox.DataSource = ...;
    dropDownBox.DataBind();

Write this:

    dropDownBox.Items.Clear();
    dropDownBox.SelectedValue = null;
    dropDownBox.DataSource = ...;
    dropDownBox.DataBind();


(The dropDownBox.Items.Clear(); operation is only required if dropDownBox.Items isn't already empty.)