SelectedValue fails on postback in DropDownList
Asked Answered
H

2

7

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?

Henbane answered 6/8, 2012 at 1:22 Comment(8)
Maxim, could you provide any feedback on my answer? I gave a proper answer, with a direct link from MSDN explaining the exception, but I got downvoted twice. Why that?!Archaeo
I would love to have any feedback from you.Archaeo
While I appreciate any answer your answer contains nothing of help as far as I see it. The upvoted posters has at least 3 sentences along with the decompiled source code confirming this problem. I'm surprised you're surprised that your post was downvoted.Henbane
Finally, thanks for getting in touch. Nothing of help? Your question: I have recently found a strange behaviour inside of the ASP.NET DropDownList that I hope someone could explain. My answer: According to the official doc, it'll happen after a viewstate is binded to the page. I thought you'd understand that it means after a postback is processed. You'll notice that my answer on the upvoted are actually the same, but he decompiled the assembly, while I referenced the official doc at MSDN.Archaeo
Maxim, you are surprised that his post contains the official msdn verifying this and so you down voted him. To me it sounds like you misread his answer, the only difference is he did not post the il, hardly worth a down vote, in fact his answer is better as it is the official msdn on the topic.Adductor
@Adductor Yes Jon I am surprised.... <Here Take a Link> isn't an answer as far as I see. I'm not trying to be an ass but I've had much more thorough answers of mine DELETED because they didn't contain enough information but I can assure you they didn't contain just a link. Frankly as far as I see it, neither of these answers is complete enough (hence why I still haven't marked one as answered) but at least a couple of lines of text (along with a workaround - which is what I asked for) is far better than a link.Henbane
@MaximGershkovich However, there is nothing else to be explained. It's a behavior by design, because Microsoft understands that, after a viewstate is binded and nothing else is performed on a data source, the control goes to a non-manipulation state. I'm really sorry if you got your answers removed, but, in this case, my answer is the only answer that you'll find. And you'll notice that it's not a pure link, I've pasted you the meaningful information though.Archaeo
@MaximGershkovich - if something is by design there isn't much anyone can do to help you...it's simply that by design, ie take it "as is".Adductor
X
2

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.

Xenon answered 6/8, 2012 at 2:18 Comment(4)
And that's exactly what I have answered, but I got downvoted. Would like to understand why...Archaeo
well setting SeletedValue = null will solves the issue but null is not a value whereas empty string is a value, my question why if we provide empty string after binding the dropdown in Page_Load works but if we assign empty string w/o binding it raises the error.Petrol
That's a mystery to me, too. I can understand it throwing an exception for empty strings (null seems more appropriate to me), but the inconsistent behavior with IsPostBack sucks.Xenon
@WaqarJanjua Unfortunately it's by design. If you take a look at my answer and verify the code drumboog provided, you'll notice that it's working as documented. It looks like they think that, after binding the viewstate to the control without setting a new datasource, the items collection might not be available for manipulation.Archaeo
A
2

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.

Archaeo answered 6/8, 2012 at 1:30 Comment(4)
@Adductor Thank you so much! I've been asking this same question for many times, I couldn't understand also.Archaeo
@Andre I too have a problem similar to this. I've 2 dropdowns. 2nd ddl is populated based on the selection of 1st ddl (user control). I'm binding 2nd ddl in 2 places. On Page_Load & inside !IsPostBack block in Render() - becoz user control will get populated after Page_Load. It works fine on the launch of the page. But if any PostBack happens, 2nd ddl is populated with nothing. To get it re-populated, I've to select the 1st ddl, so On_Selection it'll re-bind the 2nd ddl. Thereafter the 2nd one retains the data. But why the 2nd ddl loses its data on the very first PostBack? Any guess?Wing
@Wing Are both of them the default ASP.NET DropDown or have you created a custom control?Archaeo
@AndreCalil sorry for the late reply. 1st drop down is a custom control. 2nd one is a ASP.Net dropdown.Wing
X
2

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.

Xenon answered 6/8, 2012 at 2:18 Comment(4)
And that's exactly what I have answered, but I got downvoted. Would like to understand why...Archaeo
well setting SeletedValue = null will solves the issue but null is not a value whereas empty string is a value, my question why if we provide empty string after binding the dropdown in Page_Load works but if we assign empty string w/o binding it raises the error.Petrol
That's a mystery to me, too. I can understand it throwing an exception for empty strings (null seems more appropriate to me), but the inconsistent behavior with IsPostBack sucks.Xenon
@WaqarJanjua Unfortunately it's by design. If you take a look at my answer and verify the code drumboog provided, you'll notice that it's working as documented. It looks like they think that, after binding the viewstate to the control without setting a new datasource, the items collection might not be available for manipulation.Archaeo

© 2022 - 2024 — McMap. All rights reserved.