AJAX.NET Cascading Dropdownlist

Ok, so I finally began my journey towards web 2.0 programming yesterday with the Cascading Dropdownlist and thought I would share on how it works and hopefully help anyone having trouble using it! The example I am going to show will use a SQL database to get the values for the dropdown lists but the code should get you in the right direction regardless of the Data Access you choose.

First thing you need to do is disable EnableEventValidation in the page directive.

 

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="cascade.aspx.cs" Inherits="cascade" EnableEventValidation="false" %>

After that we need to add a couple of ASP DropDownLists:

<div>
    <asp:DropDownList ID="DropDownList1" runat="server">
    </asp:DropDownList><br />
    <br />
    <asp:DropDownList ID="DropDownList2" runat="server">
    </asp:DropDownList>
</div>

Now we need to add a ScriptManager and the CascadingDropDownList Control and point them to the dropdownlists, there are a few other properties of the Dropdown we need to set as well, but since we don’t have a web service yet we will wait to add those properties until later. What’s important here is that we are specifying which dropdownlist to control here with the TargetControlID property:

 

<div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:DropDownList ID="DropDownList1" runat="server">
        </asp:DropDownList><br />
        <ajaxToolkit:CascadingDropDown
        ID="CascadingDropDown1"
        runat="server"
        TargetControlID="DropDownList1">
        </ajaxToolkit:CascadingDropDown>
        <br />
        <asp:DropDownList ID="DropDownList2" runat="server">
        </asp:DropDownList><br />
        <ajaxToolkit:CascadingDropDown
        ID="CascadingDropDown2"
        runat="server"
        TargetControlID="DropDownList2">
        </ajaxToolkit:CascadingDropDown>
</div>

The next thing we need to do is create a Web Service that will provide data for our dropdownlists. For my service I created DataService.asmx with the codebehind file DataService.CS. 

DataService.asmx only points to the CS file:

 

<%@ WebService Language="C#" CodeBehind="~/App_Code/DataService.cs" Class="DataService" %>

 

The rest of the code goes into the CS file. The first thing to note is that the CascadingDropDown requires the method are as follows:

 

[WebMethod]
    public CascadingDropDownNameValue[] GetDropDownData(string knownCategoryValues, string category)

With the exception that you can call your method "GetDropDownData" anything you would like but the type and params must stay that way for the call to be made which makes getting your paramaters out of the call just a little tricky. Let’s say our first DropDownList’s category is department and the value for it is DeptID which equals 2.. Well calling the knownCategory string will return Department:2; now if there were two dropdownlists one with category Department and one with category Employee knowcategoryvalues would return Department:1;Employee:John; etc. Luckily they made it easy to access these values using a stringdictionary like you can see here:

 

StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(
         knownCategoryValues);
        int DeptID;
        if (!kv.ContainsKey("Department") ||
            !Int32.TryParse(kv["Department"], out DeptID))
        {
            return null;
        }

This example finds the entry with the key Department and then pulls out an int from it’s value, so if our Catgory is Department and our value is 3 it would pull out a 3 which we can now use in our code to get the next list of items. If you wanted to just pull the value as a string you could change the code to look as so:

 

StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(
         knownCategoryValues);
        string DeptID = kv["Department"].ToString();

 

Either way it will pull the value. Ok, now that we have that out of the way let’s look at the full code for our Web Service:

 

using System;
using System.Web;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web.Services;
using System.Web.Services.Protocols;
using AjaxControlToolkit;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

/// <summary>
/// Summary description for CarData
/// </summary>
[WebService(Namespace = "http://tempuri.org/&quot;)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService()]

public class DataService : System.Web.Services.WebService
{
    public DataService()
    {
        //Uncomment the following line if using designed components
        //InitializeComponent();
    }

    [WebMethod]
    public CascadingDropDownNameValue[] GetDepartments(string knownCategoryValues, string category)
    {
        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString))
        {
            using (SqlCommand command = new SqlCommand("GetDepartments", connection))
            {
                command.CommandType = CommandType.StoredProcedure;
                connection.Open();
                List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        int id = (int)reader["DeptID"];
                        string Department = (string)reader["Department"];
                        values.Add(new CascadingDropDownNameValue(Department, Convert.ToString(id)));
                    }
                }
                return values.ToArray();
            }
        }
    }

    [WebMethod]
    public CascadingDropDownNameValue[] GetEmployees(string knownCategoryValues, string category)
    {
        StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(
        knownCategoryValues);
        int DeptID;
        if (!kv.ContainsKey("Department") ||
            !Int32.TryParse(kv["Department"], out DeptID))
        {
            return null;
        }

        using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString))
        {
            using (SqlCommand command = new SqlCommand("GetEmployees", connection))
            {
                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.Add(new SqlParameter("@DeptID", Convert.ToString(DeptID)));
                connection.Open();
                List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        int id = (int)reader["DeptID"];
                        string firstname = (string)reader["FirstName"];
                        values.Add(new CascadingDropDownNameValue(firstname, Convert.ToString(id)));
                    }
                }
                return values.ToArray();
            }
        }
    }
}

At the top of the web service you will notice the namespace [System.Web.Script.Services.ScriptService()], without this you will only get errors, so make sure you place this in your web service! The Array returned also needs to be from CascadingDropDownNameValue so make sure when you create your array you use List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>(); and then populate the values!

Ok, now we can go back to your code and add our service path, service method, category and prompt text. Also in the second Dropdownlist we need to add a ParentControlID so it knows it will be updated by DropDownList1

 

     <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:DropDownList ID="DropDownList1" runat="server">
        </asp:DropDownList><br />
        <ajaxToolkit:CascadingDropDown
        ID="CascadingDropDown1"
        runat="server"
        TargetControlID="DropDownList1"
        ServicePath="DataService.asmx"
        ServiceMethod="GetDepartments"
        Category="Department"
        PromptText="pick Department">
        </ajaxToolkit:CascadingDropDown>
        <br />
        <asp:DropDownList ID="DropDownList2" runat="server">
        </asp:DropDownList><br />
        <ajaxToolkit:CascadingDropDown
        ID="CascadingDropDown2"
        runat="server"
        TargetControlID="DropDownList2"
        ServicePath="DataService.asmx"
        ServiceMethod="GetEmployees"
        ParentControlID="DropDownList1"
        Category="Employee"
        PromptText="pick employee">
        </ajaxToolkit:CascadingDropDown>
    </div>

And that is it! I hope this helps someone getting started with Ajax.NET

Advertisement