The Toolkit in action: Hooking up the CasdcadingDropDown

The "Atlas" Control Toolkit makes it super easy to add great usability features to your website. 

One of the things people regularly want to do is to create a "cascading" set of DropDownLists, where the value of each populates the values below.  The "Atlas" Control Toolkit contains a great extender to make this super easy to set up.  It does all of the population of the lists using an async call to a web service, which allows you to filter and cache the data on the server side and easily integrate it into your page. 

Go here to download and install the toolkit, and the Atlas April CTP if you don't already have it.  Once you've got it installed, you can see demos of all the controls in the toolkit.  Note that, like Atlas, this toolkit is an early version.  If you find issues, please report them in the Atlas Toolkit Forum so we can fix them for the next release.

But say I want to hook up a set of drop down lists.  First, I create a new Atlas Website, and add a reference to the toolkit assembly.  You'll find the assembly (called AtlasControlTookit.dll) in the "AtlasControlToolkit\bin" directory where you installed the tookit.  When prompted to replace the "Microsoft.Web.Atlas.DLL", choose 'No'.

In the default.aspx page and add some dropdowns to it:

   <div> ns="urn:schemas-microsoft-com:office:office" prefix="o" ?>

    Make: <asp:DropDownList ID="ddlMake" runat="server"/><br/>

    Model: <asp:DropDownList ID="ddlModel" runat="server"/><br/>

    Color: <asp:DropDownList ID="ddlColor" runat="server"/>

    <br />

    <asp:Button ID="Button1" runat="server" Text="Submit" />

   </div>

Now, at the top of your ASPX page, register a prefix for the reference to the tookit:

<%@ Register Assembly="AtlasControlToolkit" Namespace="AtlasControlToolkit" TagPrefix="atlasToolkit" %>

And then add the extender itself:

 

<atlasToolkit:CascadingDropDown ID="CascadingDropDown1" runat="server">

</atlasToolkit:CascadingDropDown>

At runtime, the extender will make callbacks to a web service we specify.  In that web service, it expects a WebMethod with the following signature (note that parameter names must match too!):

[WebMethod]

public CascadingDropDownNameValue[] GetColorsForModel(string knownCategoryValues, string category)

The knownCategoryValues parameter will return a string containing the currently selected category values, as well as the category to retrieve values for.  For example, if the extender is populating the "Color" field, you will be passed the values for the "Make" and "Model" fields, as well as "Color" to specify the field to return values for.

The CascadingDropDown class has a helper method for unpacking the category values:

StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

This method will return a StringDictionary containing the name/value pairs of the currently selected values.  So imagine you've got a database with tables for the Make (manufacturer), Model, and Color information, and you're accessing that database through a DataSet to which you've added methods for getting each set of values.

The web method to get the available colors for a given model would look like this:

[WebMethod]

public CascadingDropDownNameValue[] GetColorsForModel(

string knownCategoryValues, string category) {

 

      StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);

 

      int modelId;

 

      if (!kv.ContainsKey("Model") || !Int32.TryParse(kv["Model"], out modelId))

      {

      throw new ArgumentException("Couldn't find make.");

      }

 

      CarsTableAdapters.ColorTableAdapter adapter = new

CarsTableAdapters.ColorTableAdapter();

 

      Cars.ColorDataTable colorTable = adapter.GetColorsForModel(modelId);

 

List<CascadingDropDownNameValue> values = new

List<CascadingDropDownNameValue>();

 

      foreach (DataRow dr in colorTable) {

          values.Add(

new CascadingDropDownNameValue(

(string)dr["Color"],

dr["ColorID"].ToString()));

      }

 

      return values.ToArray();

}

So it's simple to return the values.  Now let's hook up our extender:

<atlasToolkit:CascadingDropDown ID="CascadingDropDown1" runat="server">

    <atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlMake"

Category="Make"

PromptText="Select a manufacturer"

ServicePath="CarsService.asmx"

ServiceMethod="GetCarMakes" />

</atlasToolkit:CascadingDropDown>

If you look at this it's pretty simple.  TargetControlID specifies which control we're extending, in this case it's the drop down that specifies the manufacturer or "make" of the car.  PromptText specifies the text to show in the dropdown when no value is selected, and the ServicePath and ServiceMethod attributes tell the extender which web service to call to fetch it's values.

We can also do this hook up from the designer.  If you switch to design view, and select the "ddlModel" DropDownList, you can make these hookups in the property browser at design time:

Note the "ParentControlID" property which specifies which DropDownList is the "parent" for this one.  By setting these parent values, you can chain or "cascade" these values, and the CascadingDropDown extender will automatically manage setting, clearing, and loading the data for you. 

If you set up the ddlModel and ddlColor lists as well and go back to source view, you'll see:

        <atlasToolkit:CascadingDropDown ID="CascadingDropDown1" runat="server">

            <atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlMake"

Category="Make"

PromptText="Select a manufacturer"

ServicePath="CarsService.asmx"

ServiceMethod="GetCarMakes" />

          

            <atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlModel"

ParentControlID="ddlMake"

PromptText="Please select a model"

ServiceMethod="GetModelsForMake"

                ServicePath="CarsService.asmx"

Category="Model" />

 

<atlasToolkit:CascadingDropDownProperties

TargetControlID="ddlColor"

ParentControlID="ddlModel"

PromptText="Please select a color"

ServiceMethod="GetColorsForModel"

ServicePath="CarsService.asmx"

Category="Color"/>

          

        </atlasToolkit:CascadingDropDown>

Once you've completed your web service methods, your cascading drop down is complete!

Finally, in order for the values to be submitted, EventValidation needs to be disabled for the page.  EventValidation ensures that the values in each control match the values that were present when the page was rendered, but since these drop downs are populating on the client side, this is never true.  We’re working on a way to resolve this issue (I'm not happy about it either!), but please ensure that you understand this and validate the data appropriately in your post back when using this control.

pbrs.png