Linked Dynamic ListBoxes using ASP.NET/C# & UpdatePanels

So, I’m using Visual Web Developer 2008 to develop my site in ASP.NET/C#.

I have two list boxes:
ListBox1:

  • gets populated with a list of cities based on data in an xml file during the OnLoad event in the codebehind.
  • this is placed on the page, outside of any UpdatePanels
  • The autopostback=true

ListBox2:

  • When a user selects a city from ListBox1, this gets populated with a list of counties that correspond to the value selected in ListBox1
  • This list box is placed in an UpdatePanel
  • The UpdatePanel is triggered by the OnSelectedIndexChanged event of ListBox1

This configuration works only for the first City (Philadelphia) in ListBox1. Anytime I select a city (Baltimore) that is second or third in the list, I get the items that match the first item on the list (Philadelphia). For some reason, the codebehind keeps re-assigning the selected value to the first item (Philadelphia). Can anyone see why this is happening?

Code:

default page ------------------------------

<asp:ScriptManager ID=“ScriptManager1” runat=“server” EnablePartialRendering=“true” >
</asp:ScriptManager>

<asp:ListBox

[INDENT]ID=“CityListBox”
runat=“server”
onselectedindexchanged=“SubMetroListBox_SelectedIndexChanged”
AutoPostBack=“True”>[/INDENT]
</asp:ListBox>

<asp:UpdatePanel ID=“UpdatePanel1” runat=“server”>

[INDENT]<ContentTemplate>

[INDENT]<asp:ListBox
ID=“countyListBox”
runat=“server”
Visible=“False”>
</asp:ListBox>[/INDENT]
</ContentTemplate>
<Triggers>

<asp:AsyncPostBackTrigger ControlID=“SubMetroListBox” EventName=“SelectedIndexChanged” />

</Triggers>[/INDENT]
</asp:UpdatePanel>

Default cs page---------------------------

protected void Page_Load(object sender, EventArgs e)
{

[INDENT]//Get the current state from the web.config file
currState = System.Configuration.ConfigurationManager.AppSettings.Get(“localstate”);

//Get and load the xml file containing the data needed for the list boxes
XmlDocument doc = new XmlDocument();
string filename = HttpContext.Current.Server.MapPath(“~/App_Data/Businesses.xml”);
doc.Load(filename);

//create and execute a query to select disctinct city values within the the current state
string selectCity = “/businesses/businessInfo[not(city=preceding-sibling::businessInfo/city) and state = '” + currCity + “']/city”;
XmlNodeList cityNodes = doc.SelectNodes(selectCity);

//determine if records were returned, then proceed if there were
if (cityNodes.Count > 0 && cityNodes != null)
{

[INDENT]//Loop through the returned values and add them to the CityListBox,
//include the current state as the value to use in selecting values for the countyListBox
foreach (XmlNode cityNode in cityNodes)
{

CityListBox.Items.Add(new ListItem(metroNode.InnerText.ToString(), currState));

            }

[/INDENT]
}
//if there were no records returned, set the visible value to the CityListBox to false.
else
{

CityListBox.Visible = false;

        }

//Loop through the items in the CityListBox. If the item is selected, query the file for corresponding distinct county values
foreach (ListItem Item in CityListBox.Items)
{

[INDENT] if (Item.Selected == true)
{
[INDENT]// Because there can be the same city/county pairing in different states, include the state
// value in the query to ensure the correct values are being returned.
string SelectedCity = Item.Text.ToString();
string selectedState = Item.Value.ToString();

            string selectCounty = "/businesses/businessInfo[not(county=preceding-sibling::businessInfo/county) and city = '" + SelectedCity + "' and state = '" + selectedState + "']/county";
            XmlNodeList countyNodes = doc.SelectNodes(selectCounty);

//if values were returned, loop through the results and add the values to the countyListBox.
if (countyNodes.Count > 0 && countyNodes != null)
{
[INDENT] foreach (XmlNode countyNode in countyNodes)
{
[INDENT]countyListBox.Items.Add(new ListItem(countyNode.InnerText.ToString(), countyNode.InnerText.ToString());[/INDENT]
}
//set the countyListBox to visible
countyListBox.Visible = true;[/INDENT]
}
[/INDENT] }[/INDENT]
}[/INDENT]
}

protected void CityListBox_SelectedIndexChanged(object sender, EventArgs e)
{

}

Make sure you aren’t repopulating the first box on every request by checking the IsPostBack property.

Thanks.

I added the if (!Page.IsPostBack) around the snippet below and i get an error:

if (!Page.IsPostBack)
{

[INDENT]string selectCity = “/businesses/businessInfo[not(city=preceding-sibling::businessInfo/city) and state = '” + currCity + “']/city”;
XmlNodeList cityNodes = doc.SelectNodes(selectCity);

//determine if records were returned, then proceed if there were
if (cityNodes.Count > 0 && cityNodes != null)
{

//Loop through the returned values and add them to the CityListBox,
//include the current state as the value to use in selecting values for the countyListBox
foreach (XmlNode cityNode in cityNodes)
{

    CityListBox.Items.Add(new ListItem(metroNode.InnerText.ToString(), currState));

}

}
//if there were no records returned, set the visible value to the CityListBox to false.
else
{

CityListBox.Visible = false;

}[/INDENT]
}

-----the error is---------

Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation=“true”/> in configuration or <%@ Page EnableEventValidation=“true” %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.


Am I missing a declaration somewhere in my config file or aspx page?

Hmm, I don’t think so, but it’s been a while since I did much with MSAJAX. Forgot the other protip about MSAJAX and update panels and other server controls: Best building strategy is to make it work without AJAX then layer it in. There are lots of layers of redirection and leaky abstractions you are dealing with, so it is best to start from a known good point.

In this case, it seems like it is probably swallowing an exception that is giving you a different error. But none of what you did should have effected anything that gives you that error.