0

I'm trying to set up cascading dropdown lists on a form for HR-related requests, with the positions displayed depending on the department selected. It might help if I already knew what I was doing, but this whole project is my first foray into ASP.NET and C#, so I'm learning as I go. That said, my position dropdown is coded like so:

<asp:ScriptManager ID="SCRMAN_PositionDropdown" runat="server" />
    <asp:DropDownList ID="SEL_Position" tabindex="7" runat="server" AutoPostBack="true">
        <asp:ListItem>Select a Department first</asp:ListItem>
    </asp:DropDownList>
    <span style="font-size:larger;">&larr;</span>If "Other" specify in the Notes box

EDIT: Here's how my Department dropdown is coded after some revision based on @dman2036 pointing out that I'd apparently tied this whole process to the wrong dropdown changing. For some reason the ending tag isn't showing, but it's there. <fsst_custom:DropDownListGrouped ID="SEL_Department" TabIndex="6" runat="server" OnSelectedIndexChanged="SEL_Department_SelectedIndexChanged" required > <%--SCRIPT INSERTS OPTIONS --%> `

The C# code that should be controlling this is as follows (in pertinent part). SEL_Department is populating correctly but for some reason (probably some ludicrous mistake in my scripting) the SelectedIndexChange is not firing. Did I maybe not include some "using" statement or am I calling it incorrectly? Note: I assume it's not firing because changing SEL_Department should at least clear out SEL_Position's "Select a Department First" item.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.DirectoryServices;
using System.Linq;
using System.Management;
using System.Security.Principal;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net.Mail;
using FSST;
using FSST.Controls;


public partial class Casino_HR_Request : System.Web.UI.Page
{

#region Constructor

public Casino_HR_Request()
{
    Load += new EventHandler(Page_Load);
}

#endregion

#region Department_And_Position    

protected void SEL_Department_SelectedIndexChanged(object sender, EventArgs e)
{
    SEL_Position.Items.Clear();

    switch(SEL_Department.SelectedValue)
    {
        case "Executive":
            SEL_Position.Items.Add(new ListItem("Select a position", ""));
            SEL_Position.Items.Add(new ListItem("General Manager", "General Manager"));
            SEL_Position.Items.Add(new ListItem("Assistant General Manager", "Assistant General Manager"));
            SEL_Position.Items.Add(new ListItem("Internal Auditor", "Internal Auditor"));
            SEL_Position.Items.Add(new ListItem("Compliance Officer", "Compliance Officer"));
            SEL_Position.Items.Add(new ListItem("Executive Assistant", "Executive Assistant"));
            SEL_Position.Items.Add(new ListItem("Other", "Other"));
            break;
        case "Finance":
            SEL_Position.Items.Add(new ListItem("Select a position", ""));
            SEL_Position.Items.Add(new ListItem("Controller", "Controller"));
            SEL_Position.Items.Add(new ListItem("Assistant Controller", "Assistant Controller"));
            SEL_Position.Items.Add(new ListItem("Cage Manager", "Cage Manager"));
            SEL_Position.Items.Add(new ListItem("Cage Supervisor", "Cage Supervisor"));
            SEL_Position.Items.Add(new ListItem("Cage Cashier", "Cage Cashier"));
            SEL_Position.Items.Add(new ListItem("Count Manager", "Count Manager"));
            SEL_Position.Items.Add(new ListItem("Assistant Count Manager", "Assistant Count Manager"));
            SEL_Position.Items.Add(new ListItem("Count Team", "Count Team"));
            SEL_Position.Items.Add(new ListItem("Senior Staff Accountant", "Senior Staff Accountant"));
            SEL_Position.Items.Add(new ListItem("Accounts Payable", "Accounts Payable"));
            SEL_Position.Items.Add(new ListItem("Accounts Receivable", "Accounts Receivable"));
            SEL_Position.Items.Add(new ListItem("Purchasing", "Purchasing"));
            SEL_Position.Items.Add(new ListItem("Receiving Clerk", "Receiving Clerk"));
            SEL_Position.Items.Add(new ListItem("Senior Accounting Auditor", "Senior Accounting Auditor"));
            SEL_Position.Items.Add(new ListItem("Accounting Auditor", "Accounting Auditor"));
            SEL_Position.Items.Add(new ListItem("Other", "Other"));
            break;
    // A BUNCH MORE CASES GO HERE
    }
}
#endregion

#region Page_Load

void Page_Load(object sender, EventArgs e)
{   
    //----------STATUS CHANGE MENU OPTIONS----------
    SEL_StatusChange.Items.Add(NewGroupedListItem("New Hire", "New Hire", "Onboard or Separate"));
    SEL_StatusChange.Items.Add(NewGroupedListItem("Separation", "Separation", "Onboard or Separate"));
    SEL_StatusChange.Items.Add(NewGroupedListItem("Position Change", "Position Change", "Changes in employment"));
    SEL_StatusChange.Items.Add(NewGroupedListItem("Add 2nd- or 3rd-Rate", "Add 2nd- or 3rd-Rate", "Changes in Employment"));
    SEL_StatusChange.Items.Add(NewGroupedListItem("Remove 2nd- or 3rd-Rate", "Remove 2nd- or 3rd-Rate", "Changes in employment"));
    SEL_StatusChange.Items.Add(NewGroupedListItem("Add listed access", "Add listed access", "Change in needs only"));
    SEL_StatusChange.Items.Add(NewGroupedListItem("Remove listed access", "Remove listed access", "Change in needs only"));
    //----------DEPARTMENT MENU OPTIONS----------
    SEL_Department.Items.Add(NewGroupedListItem("", "Department Name", ""));
    SEL_Department.Items.Add(NewGroupedListItem("Executive", "Executive", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Finance", "Finance", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Food and Beverage", "Food and Beverage", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Gaming Commission", "Gaming Commission", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Gas Stations", "Gas Stations", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Hotel", "Hotel", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Human Resources", "Human Resources", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("IT", "IT", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Maintenance", "Maintenance", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Marketing", "Marketing", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Player's Club", "Player's Club", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Porters", "Porters", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Security", "Security", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Slots", "Slots", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Surveillance", "Surveillance", "Select a department"));
    SEL_Department.Items.Add(NewGroupedListItem("Table Games", "Table Games", "Select a department"));
}

protected ListItem NewGroupedListItem(string value, string text, string group)
{
    ListItem li = new ListItem(value, text);
    li.Attributes.Add("optgroup", group);
    return li;
}

#endregion

//TWO MORE REGIONS NOT RELEVANT TO THIS GO HERE
}

Here's the code for DropdownListGrouped, which a friend sent me and I just incorporated as he told me.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

    namespace FSST.Controls
    {

        /// <summary>
        /// Provides options for grouping list items.
        /// </summary>
        /// <remarks>
        /// Much came from here:
        /// http://stackoverflow.com/questions/130020/dropdownlist-control-with-optgroups-for-asp-net-webforms
        /// </remarks>
        public class DropDownListGrouped : System.Web.UI.WebControls.DropDownList
        {
            const string OptionGroupTag = "optgroup";
            const string OptionTag = "option";

            #region DataGroupingField

            public string DataGroupingField
            {
                get
                {
                    object o = ViewState["DataGroupingField"];
                    return (o == null) ? "" : (string)o;
                }
                set
                {
                    ViewState["DataGroupingField"] = value;
                }
            }

            #endregion

            #region PerformDataBinding

            protected override void PerformDataBinding(System.Collections.IEnumerable dataSource)
            {
                base.PerformDataBinding(dataSource);
                if (DataGroupingField.Length == 0)
                    return;

                // Go back through the data source and assign the attributes

                // We know the items were added to the end, so just work through them
                if (dataSource != null)
                {
                    ICollection collection = dataSource as ICollection;
                    int startIndex = 0;
                    if (collection != null)
                        startIndex = this.Items.Count - collection.Count;

                    string dataGroupingField = DataGroupingField;
                    foreach (object current in dataSource)
                        Items[startIndex++].Attributes.Add(OptionGroupTag, DataBinder.GetPropertyValue(current, DataGroupingField, null));
                }
            }

            #endregion

            #region RenderContents

            protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
            {
                ListItemCollection items = this.Items;
                int count = items.Count;
                string tag;
                string optgroupLabel;
                if (count > 0)
                {
                    bool flag = false;
                    string prevOptGroup = null;
                    for (int i = 0; i < count; i++)
                    {
                        tag = OptionTag;
                        optgroupLabel = null;
                        ListItem item = items[i];
                        if (item.Enabled)
                        {
                            if (item.Attributes != null && item.Attributes.Count > 0 && item.Attributes[OptionGroupTag] != null)
                            {
                                optgroupLabel = item.Attributes[OptionGroupTag];

                                if (prevOptGroup != optgroupLabel)
                                {
                                    if (prevOptGroup != null)
                                        writer.WriteEndTag(OptionGroupTag);
                                    writer.WriteBeginTag(OptionGroupTag);
                                    if (!string.IsNullOrEmpty(optgroupLabel))
                                        writer.WriteAttribute("label", optgroupLabel);
                                    writer.Write('>');
                                }
                                item.Attributes.Remove(OptionGroupTag);
                                prevOptGroup = optgroupLabel;
                            }
                            else
                            {
                                if (prevOptGroup != null)
                                    writer.WriteEndTag(OptionGroupTag);
                                prevOptGroup = null;
                            }

                            writer.WriteBeginTag(tag);
                            if (item.Selected)
                            {
                                if (flag)
                                    this.VerifyMultiSelect();
                                flag = true;
                                writer.WriteAttribute("selected", "selected");
                            }
                            writer.WriteAttribute("value", item.Value, true);
                            if (item.Attributes != null && item.Attributes.Count > 0)
                                item.Attributes.Render(writer);
                            if (optgroupLabel != null)
                                item.Attributes.Add(OptionGroupTag, optgroupLabel);
                            if (this.Page != null)
                                this.Page.ClientScript.RegisterForEventValidation(this.UniqueID, item.Value);

                            writer.Write('>');
                            HttpUtility.HtmlEncode(item.Text, writer);
                            writer.WriteEndTag(tag);
                            writer.WriteLine();
                            if (i == count - 1 && prevOptGroup != null)
                                writer.WriteEndTag(OptionGroupTag);
                        }
                    }
                }
            }

            #endregion

            #region SaveViewState

            protected override object SaveViewState()
            {
                object[] state = new object[this.Items.Count + 1];
                object baseState = base.SaveViewState();
                state[0] = baseState;
                bool itemHasAttributes = false;

                for (int i = 0; i < this.Items.Count; i++)
                {
                    if (this.Items[i].Attributes.Count > 0)
                    {
                        itemHasAttributes = true;
                        object[] attributes = new object[this.Items[i].Attributes.Count * 2];
                        int k = 0;

                        foreach (string key in this.Items[i].Attributes.Keys)
                        {
                            attributes[k] = key;
                            k++;
                            attributes[k] = this.Items[i].Attributes[key];
                            k++;
                        }
                        state[i + 1] = attributes;
                    }
                }

                if (itemHasAttributes)
                    return state;
                return baseState;
            }

            #endregion

            #region LoadViewState

            protected override void LoadViewState(object savedState)
            {
                if (savedState == null)
                    return;

                if (!(savedState.GetType().GetElementType() == null) &&
                    (savedState.GetType().GetElementType().Equals(typeof(object))))
                {
                    object[] state = (object[])savedState;
                    base.LoadViewState(state[0]);

                    for (int i = 1; i < state.Length; i++)
                    {
                        if (state[i] != null)
                        {
                            object[] attributes = (object[])state[i];
                            for (int k = 0; k < attributes.Length; k += 2)
                            {
                                this.Items[i - 1].Attributes.Add
                                    (attributes[k].ToString(), attributes[k + 1].ToString());
                            }
                        }
                    }
                }
                else
                {
                    base.LoadViewState(savedState);
                }
            }

            #endregion
        }
    }
  • 1
    I'm confused... SEL_Position has no items in it unless SelectedIndexChanged is called, so how can SelectedIndexChanged fire when there are no items to select? Did you intend that event to be on SEL_Department? Meaning, when I choose a department you then load the positions? – dmeglio Dec 02 '15 at 17:31
  • 2
    Wrap the stuff you have in page_load in `if (!Page.IsPostBack)`. Currently you are repopulating the ddl on every page load – Andrei Dec 02 '15 at 17:32
  • No where are you showing the code for `DropDownListGrouped` so it's impossible to know why this custom control is not firing an event. Does it require `AutoPostBack` like the standard `DropDownList`? I have no way to know. – dmeglio Dec 02 '15 at 18:11
  • I've edited in the code for `DropDownListGrouped` into the post. – Nick Zachariasen Dec 02 '15 at 20:51
  • Sorry for question, but have you set on AutoPostBack property on your Dropdownlist? – Khazratbek Dec 03 '15 at 00:34
  • Khazratbek, THANK YOU! I thoguht I'd had it on there but you asking made me double-check. Now it works! – Nick Zachariasen Dec 03 '15 at 15:17

1 Answers1

3

You are re-populating the lists in Page_Load which is resetting the selected index. I would move that logic to a separate method and only call if if the request is not a post-back:

void Page_Load(object sender, EventArgs e)
{
    if(!Page.IsPostBack)
        BindLists();   
}

void BindLists()
{
    //----------STATUS CHANGE MENU OPTIONS----------
    SEL_StatusChange.Items.Add(NewGroupedListItem("New Hire", "New Hire", "Onboard or Separate"));
    SEL_StatusChange.Items.Add(NewGroupedListItem("Separation", "Separation", "Onboard or Separate"));
    // etc.
}

UI Event handling in ASP.NET takes some practice to get right since every post-back is a completely new web request. It's different than WinForms where everything remains in memory. The entire page is re-rendered with every post back, and you need to handle state appropriately.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • This didn't fix the problem with the Department list not populating the Position list, but it's good to know for future reference. Thanks. – Nick Zachariasen Dec 02 '15 at 20:53