October 7, 2011 by Christoff Truter C# ASP.NET
When working with relational data on a frontend one of the common practices (among TreeViews) are to make use
of DropDowns that update in relation to one another - cascading.
In the following image we've got three DropDownLists that demonstrates this cascading
effect.
When an user selects a country, it updates the list of provinces (or states)
available for that country, which in turn updates the list of available cities for the
selected province.
One way to achieve this (many ways to skin a cat) is to attach handlers to the SelectedIndexChanged
events of our DropDownLists and manually handling the cascade relation like seen in the following snippet.
protected void ddlCountry_SelectedIndexChanged(object sender, EventArgs e) { ddlCountry.Cascade(ddlProvince, (CountryId) => Province.Get(CountryId)); ddlProvince.Cascade(ddlCity, (ProvinceId) => City.Get(ProvinceId)); } protected void ddlProvince_SelectedIndexChanged(object sender, EventArgs e) { ddlProvince.Cascade(ddlCity, (ProvinceId) => City.Get(ProvinceId)); }
public static class ExtensionMethods { public static void Cascade<T>(this DropDownList parentDropDownList, DropDownList childDropDownList, Func<Int32, T> dataSource) { childDropDownList.Items.Clear(); childDropDownList.AppendDataBoundItems = true; childDropDownList.Items.Add(new ListItem("- Please Select -", "")); if (!String.IsNullOrEmpty(parentDropDownList.SelectedValue)) { childDropDownList.DataSource = dataSource(Convert.ToInt32(parentDropDownList.SelectedValue)); childDropDownList.DataBind(); } } }
<asp:DropDownList runat="server" ID="ddlCountry"> </asp:DropDownList> <asp:DropDownList runat="server" ID="ddlProvince"> </asp:DropDownList> <asp:DropDownList runat="server" ID="ddlCity"> </asp:DropDownList> <asp:CascadingDropDown ID="cddlCountries" runat="server" TargetControlID="ddlCountry" Category="Country" PromptText="- Please Select -" ServicePath="~/Services/Service.asmx" ServiceMethod="GetCountries"> </asp:CascadingDropDown> <asp:CascadingDropDown ID="cddlProvinces" runat="server" TargetControlID="ddlProvince" ParentControlID="ddlCountry" Category="Province" PromptText="- Please Select -" ServicePath="~/Services/Service.asmx" ServiceMethod="GetProvinces"> </asp:CascadingDropDown> <asp:CascadingDropDown ID="cddlCities" runat="server" TargetControlID="ddlCity" ParentControlID="ddlProvince" Category="City" PromptText="- Please Select -" ServicePath="~/Services/Service.asmx" ServiceMethod="GetCities"> </asp:CascadingDropDown>
TargetControlID | ID of the DropDownList being extended / populated. |
ParentControlID | ID of the DropDownList thats above this control in the hierarchy, the extender needs the SelectedValue of the parent DropDownList in order to be able to databind the target control. |
Category | Category represented by the control, this property is used as key(s) to distinguish the values of each DropDownList SelectedValue in the knownCategoryValues parameter passed to the webmethod - parseable by the CascadingDropDown.ParseKnownCategoryValuesString method. |
PromptText | The text of the default item in the DropDownList (almost feels like something that should have been part of the DropDownlist WebControl, hint hint). PromptValue sets the value of the default item. |
ServicePath | Path to the webservice, uhm... yes you're going to need to write a webservice which will be used by the extender to databind DropDownLists client side. |
ServiceMethod | Method in the webservice thats going to be called in order to populate the DropDownList. |
[WebService(Namespace = "http://cstruter.com/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class Service : System.Web.Services.WebService { [WebMethod] public CascadingDropDownNameValue[] GetCountries( string knownCategoryValues, string category) { return Country.Get().Select(p => new CascadingDropDownNameValue(p.Title, p.CountryId.ToString()) ).ToArray(); } [WebMethod] public CascadingDropDownNameValue[] GetProvinces( string knownCategoryValues, string category) { StringDictionary values = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues); Int32 CountryId = Convert.ToInt32(values["Country"]); return Province.Get(CountryId).Select(p => new CascadingDropDownNameValue(p.Title, p.ProvinceId.ToString()) ).ToArray(); } [WebMethod] public CascadingDropDownNameValue[] GetCities( string knownCategoryValues, string category) { StringDictionary values = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues); Int32 ProvinceId = Convert.ToInt32(values["Province"]); return City.Get(ProvinceId).Select(p => new CascadingDropDownNameValue(p.Title, p.CityId.ToString()) ).ToArray(); } }
November 3, 2011
sPjiyYuiEIKE December 21, 2011 by Cordy
Could you write about Phsycis so I can pass Science class?