Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SelectedValue fails on postback in DropDownList

I have recently found a strange behaviour inside of the ASP.NET DropDownList that I hope someone could explain.

Basically the problem I am running into is when databinding prior to postback and then setting the SelectedValue to a value that doesn't exist within the list of dataitems the call simply has no effect. However on postback the same call will fail with a ArgumentOutOfRangeException()

'cmbCountry' has a SelectedValue which is invalid because it does not exist in the list of items. Parameter name: value

I'm using the following code.

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        cmbCountry.DataSource = GetCountries();
        cmbCountry.DataBind();

        cmbCountry.SelectedValue = ""; //No effect
    }
    else
    {
        cmbCountry.SelectedValue = ""; //ArgumentOutOfRangeException is thrown
    }
}

protected List<Country> GetCountries()
{
    List<Country> result = new List<Country>();

    result.Add(new Country() { ID = Guid.NewGuid(), Description = "Test" });
    result.Add(new Country() { ID = Guid.NewGuid(), Description = "Test1" });
    result.Add(new Country() { ID = Guid.NewGuid(), Description = "Test2" });
    result.Add(new Country() { ID = Guid.NewGuid(), Description = "Test3" });

    return result;
}

public class Country
{
    public Country() { }
    public Guid ID { get; set; }
    public string Description { get; set; }
}

Could someone please clarify the cause of this behaviour for me and advise if there are any workarounds?

like image 522
Maxim Gershkovich Avatar asked Aug 06 '12 01:08

Maxim Gershkovich


2 Answers

I'm not sure why it was designed this way, but the DropDownList only throws this exception on PostBack... here's the setter code from ILSpy:

public virtual string SelectedValue
{
    get { ... }
    set
    {
        if (this.Items.Count != 0)
        {
            if (value == null || (base.DesignMode && value.Length == 0))
            {
                        this.ClearSelection();
                return;
            }
            ListItem listItem = this.Items.FindByValue(value);


/********** Checks IsPostBack here **********/
            bool flag = this.Page != null &&
                        this.Page.IsPostBack &&
                        this._stateLoaded;
            if (flag && listItem == null)
            {
                throw new ArgumentOutOfRangeException("value",
                    SR.GetString("ListControl_SelectionOutOfRange", new object[]
                        {
                            this.ID,
                            "SelectedValue"
                        }));
            }
            if (listItem != null)
            {
                this.ClearSelection();
                listItem.Selected = true;
            }
        }
        this.cachedSelectedValue = value;
    }
}

You can get around this by setting the SelectedValue to null instead of an empty string.

like image 126
Glen Hughes Avatar answered Nov 10 '22 09:11

Glen Hughes


DropDownList > SelectedValue Property > ArgumentOutOfRangeException

The selected value is not in the list of available values and view state or other state has been loaded (a postback has been performed). For more information, see the Remarks section.

Source: MSDN

DropDownList > SelectedValue Property > Remarks

(...) When the selected value is not in the list of available values and a postback is performed, an ArgumentOutOfRangeException exception is thrown. (...)

Source: MSDN

Also, I've made the following test:

  1. On !IsPostBack, added a list with 4 items as datasource, IDs 1~4
  2. Set SelectedValue = 5
  3. Added a new item, using combo.Items.Add(new ListItem()...) with ID 5

I expected to see ID 5 as the current selected item at the combo, but it didn't happened.

After all, looks like this behavior is by design. I haven't found more information about, so the following are just my thoughts: it feels like, after arbitrary setting the control's datasource, developer is free to select a non-existing item, which will have simply no effect. However, after binding the viewstate on a postback processing, control's list is validated (or something like it), so it must be manipulated accordingly.

like image 41
Andre Calil Avatar answered Nov 10 '22 09:11

Andre Calil