I really dislike the ListControl SelectedValue implementation – this damn property is causing me all sorts of grief on occasion with its inconsistencies.
Here’s a scenario I’ve just run into again: I have a form that binds values early in the form cycle. It’s mostly an AJAX driven form so there are only a few isolated POSTbacks that occur that repost the entire page because they update most of the content anyway.
So the list is loaded up in OnInit() and the initial SelectedValue is set as part of the startup code. POSTBACKS then set the value to the last user set value and all that works well enough. Here’s the basic code that deals with the initial and POSTback assignments:
private void GetResourceSet()
{
this.ResourceSet = Request.Form[this.lstResourceSet.UniqueID];
if (ResourceSet == null)
this.ResourceSet = Request.QueryString["ResourceSet"];
if (this.ResourceSet == null)
this.ResourceSet = ViewState["ResourceSet"] as string;
this.ResourceSet = this.ResourceSet.ToLower();
if (!string.IsNullOrEmpty(this.ResourceSet))
ViewState["ResourceSet"] = this.ResourceSet;
DataTable dt = Manager.GetAllResourceSets(ResourceListingTypes.AllResources);
this.lstResourceSet.DataSource = dt;
this.lstResourceSet.DataValueField = "ResourceSet";
this.lstResourceSet.DataBind();
if (this.ResourceSet != null)
this.lstResourceSet.SelectedValue = this.ResourceSet;
}
The problem comes in if I need to change the selected value as part of an event LATER in the page cycle. Basically I have an event that fires and allows renaming one of the items which in turn changes the entire list interface of several lists of the form so they need to be reloaded. Here is the key that reloads the ResourceSet list:
protected void btnRenameResourceSet_Click(object sender, EventArgs e)
{
if (!this.Manager.RenameResourceSet(this.txtOldResourceSet.Text,
this.txtRenamedResourceSet.Text))
this.ErrorDisplay.ShowError(this.Manager.ErrorMessage);
else
{
this.lstResourceSet.ClearSelection();
// this.lstResourceSet.SelectedValue = null;
// this.lstResourceSet.SelectedIndex = -1;
// *** Refresh and reset the resource list
// *** Reloads the list from the data base calls databind()
this.GetResourceSet();
this.ErrorDisplay.ShowMessage("ResourceSet renamed");
}
}
The problem is when I call GetResourceSet() again I get an error:
'lstResourceSet' has a SelectedValue which is invalid because it does not exist in the list of items.
Ok, fine but how the heck can I clear the selection in the first place so that ASP.NET DOESN’T complain about the existing value so it can safely DataBind?
I’ve tried ClearSelection() – doesn’t work. I tried setting the SelectedValue to null which doesn’t work at all (the old selection stays active) and setting the SelectedIndex also has no effect because the SelectedValue lookup is what’s really being checked.
This seems to work however:
this.lstResourceSet.SelectedValue = this.txtRenamedResourceSet.Text.ToLower();
// *** Refresh and reset the resource list
this.GetResourceSet();
although I don’t really understand why that is working. SelectedValue assignments are supposed to fail if the value doesn’t exist in the list of items yet and in this case the item DOESN’T exist yet, because the list hasn’t been rebound with the new value.
I took a look at the SelectedValue implementation in System.Web with Reflector, and looking at this implementation I’m really scratching my head. It looks like there really is no way to clear out a selection of the SelectedValue:
set
{
if (this.Items.Count != 0)
{
if ((value == null) || (base.DesignMode && (value.Length == 0)))
{
this.ClearSelection();
return;
}
ListItem item1 = this.Items.FindByValue(value);
if ((((this.Page != null) && this.Page.IsPostBack) && this._stateLoaded) && (item1 == null))
{
throw new ArgumentOutOfRangeException("value", SR.GetString("ListControl_SelectionOutOfRange", new object[] { this.ID, "SelectedValue" }));
}
if (item1 != null)
{
this.ClearSelection();
item1.Selected = true;
}
}
this.cachedSelectedValue = value;
}
Notice the call to:
ListItem item1 = this.Items.FindByValue(value);
Which in theory should fail because the txtRenamedResourceSet.Text value doesn’t exist in the list yet.
Even odder is hooking the debugger up to this code:
this.lstResourceSet.SelectedValue = this.txtRenamedResourceSet.Text.ToLower();
and looking at lstREsourceSet.SelectedValue after the assignment – it’s showing the old value rather than the updated one, YET the DataBind() operation actually works with this same existing SelectedValue as when I hadn’t assigned this value.
I suppose this code would be safer:
// *** Force the selected value to be set
this.lstResourceSet.Items.Add(new ListItem("", this.txtRenamedResourceSet.Text.ToLower()));
this.lstResourceSet.SelectedValue = this.txtRenamedResourceSet.Text.ToLower();
Either way it seems it’s all rather convoluted to do something as simple as resetting a list selection value. I have this sinking feeling that I must be overlooking something simple that’s escaping me…
Other Posts you might also like