需求是这样的,有三个DropDownList控件,分别用来选择国家,省份,和城市。他们具有依赖关系,当我选择某个国家的时候,我需要无刷新的动态加载这个国家的所有的省份,同样,当我选择某个省份的时候,我需要无刷新的选择这个省份的所有的城市。而这些国家,省份和城市的数据全部是储存在sql server数据库中。
我看了这个需求后,我打算利用AjaxToolKit中的CascadingDropDown控件加上asp.net2.0自带的DropDownList来实现。
具体过程如下:
CascadingDropDown数据控件默认的填充数据源是基于XML的,它是通过webservice去调用XML文件,通过节点来区分子节,然后加载相关的数据。
网上关于如何来加载XML数据源的例子很多,但是这里的需求决定了,我们得需要利用基于数据库的数据填充方式。
首先,我们需要在我们的web-site中建立一个webservice,它用来提供CascadingDropDown的数据源。(在最新七月的推出的版本中,这里可以不用添加webService,而是直接利用在.cs文件中添加内嵌方法的方式来设定,但不管怎么样,他们在具体实现method中是殊途同归的,这里不做过多讲述)
一般来说,有多少个CascadingDropDown,就有多少个[webMethod],但是,你也可以根据系统的条件以及自己的设计爱好,利用category属性合理的去重载这些方法。
我们在.cs代码页面添加如下代码,以方便前台页面的调用和配置。
[System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
public static CascadingDropDownNameValue[] GetCountries(string knownCategoryValues, string category)
{
//
// 如果采用了webService架构,这里就直接去调用webService中的[webMethod],07年6月份后的版本默认都不采用webService
// 而是直接将webService中的[webMethod]实现移动到这个方法体内
//
}
然后建立数据连结池,可以利用SqlDataAdapter或者SqlDataReader来访问数据库(由于数据量小,建议使用SqlDataReader)
string selectCommand = "SELECT * FROM [dbo].[tbCountryRegion] WHERE [RegionType] = 3";
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString))
{
SqlCommand sqlcmd = new SqlCommand(selectCommand, conn);
conn.Open();
SqlDataReader reader = sqlcmd.ExecuteReader();
… …
把检索出来的数据转换成CascadingDropDownNameValue类型(该类型在using AjaxControlToolkit命名空间中)
List <CascadingDropDownNameValue> values = new List <CascadingDropDownNameValue>();
while (reader.Read())
{
values.Add(new CascadingDropDownNameValue(reader[1].ToString(), reader[0].ToString()));
}
reader.Close();
当数据为空的时候,建议设定一个默认值
if (values.Count == 0)
{
values.Add(new CascadingDropDownNameValue("中国", "000"));
}
最终利用返型来存储这些数据,
return values.ToArray();
}
最后,我们需要在aspx页面上配置我们的控件信息和属性
首先是我们的页面显示空间DropDownList
<asp:DropDownList ID=" CountryRegion " runat="server">
</asp:DropDownList>
<asp:DropDownList ID=" Province " runat="server">
</asp:DropDownList>
<asp:DropDownList ID=" CityName " runat="server">
</asp:DropDownList>
然后添加一个我们运行CascadingDropDown控件需要的脚本管理
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
最后添加主角CascadingDropDown控件,并配置相关属性和信息
<ajaxToolkit:CascadingDropDown ID="cascadingDropDownCountry" runat="server" ServiceMethod="GetCountries"
TargetControlID="CountryRegion" UseContextKey="True" Category ="provincename" PromptText="请选择国家" LoadingText="正在加载国家信息...">
</ajaxToolkit:CascadingDropDown>
<ajaxToolkit:CascadingDropDown ID="cascadingDropDownProvince" runat="server" ParentControlID="CountryRegion"
TargetControlID="Province" Category="Provinces" ServiceMethod ="GetProvincesForCountry" UseContextKey="True" PromptText="请选择省份" LoadingText="正在加载省份(地区)信息...">
</ajaxToolkit:CascadingDropDown>
<ajaxToolkit:CascadingDropDown ID="cascadingDropDownCity" runat="server" Category="city" ParentControlID="Province"
ServiceMethod="GetCitiesForProvince" TargetControlID="CityName" UseContextKey="True" PromptText="请选择城市" LoadingText="正在加载城市信息">
</ajaxToolkit:CascadingDropDown>
刚才,我们添加的[webMethod]是GetCountries,它作为CascadingDropDown控件cascadingDropDownCountry的获取数据的方法 (cascadingDropDownCountry中的ServiceMethod="GetCountries"来定义这个属性),而将它关联的是DropDownList 中 CountryRegion控件(cascadingDropDownCountry中的TargetControlID="CountryRegion"来定义)。而另外两个Province和CityName控件所关联的cascadingDropDownProvince和 cascadingDropDownCity控件呢?他们的[ServiceMethod]方法又是什么呢?我们可以看到在这两个CascadingDropDown控件的后面有一个ServiceMethod=""的属性,这个就是配置了他们的获取数据的方法。又上面的配置信息,我们可以得到他们的方法分别是CountryRegion和GetCitiesForProvince方法,这个需要我们在.cs中重新定义,类似于我们操作第一个一样。
不同的是,由于我们的第一个没有其关联的父选项DropDownList,所以,在获取数据的时候,直接就可以利用sql句获取我们想得到的数据,但是,第二个和第三个却都拥有父选项,换句话说,他们的内容是受到他们的父选项控制的,比如,我们只有在第一个DropDownList中选择了国家,我们的才能在第二个DropDownList中,动态的加载这个国家的所有地区,我们也只有选择了第二个DropDownList中的地区或省份,我们才能在第三个DropDownList中动态添加该地区或省份的所有城市。他们是具有父子之间的依赖关系的。
那么,他们之间是怎么联系的呢?答案就在代码中。
请注意,前台CascadingDropDown控件代码中的这个配置
ParentControlID="Province"
Category="city"
这两个配置的意思就是,ParentControlID定义了CascadingDropDown控件所绑定的DropDownList的控件的父选项是是什么。
而Category表示的是,它所处的类别,是用户自定义的,方便在多个CascadingDropDown控件调用一个[webMethod]的时候,实现重载。
当我们的子下拉控件绑定到父下拉的时候,根据这个控件的特色,就会产生如下的联系:
1.当父下拉控件不被选择的时候,子下拉控件是呈灰色不可操作的
2.当父下拉空间被选择的时候,子下拉空间就在其被选择后,根据父控件被选择的内容,自动加载预定信息
他们之间的联系,就是通过ParentControlID设定后,在子控件获取数据的方法体中knownCategoryValues获得。
[System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
public static CascadingDropDownNameValue[] GetCountries(string knownCategoryValues, string category)
knownCategoryValues的传递是以字符串的形式传递的,它的主要形式如下:
"provincename:000;”
"provincename:000;”Provinces:000010;"
传递一次,它就将会随之自动的增加一次。Provincename是我们下拉框选项的显示内容(text),000是下拉框在这个显示内容下的值(value).
他们是从哪里来的呢,是从我们的父下拉控件中传递过来的,如
values.Add(new CascadingDropDownNameValue("中国", "000"));
这里面name就是“中国”,value就是“000”。
既然如此,我们就可以按照如下方式进行操作,获取父控件传递的信息,如下
方法一:截取字符串到字符串数组
string[] categoryValues = knownCategoryValues.Split(':', ';');
方法二:利用数据字典
StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
这两种方法是殊途同归。
我采取的是第一种方法,简单易懂。
在获取上面传来的值信息之后,我们就可以进行数据检索操作,并去获取我们想要的数据了
string selectCommand = "SELECT * FROM [dbo].[tbCountryRegion] WHERE [RegionType] = 2 AND [RegionID] LIKE '" + categoryValues[1]+ "%'";
下面的过程和第一个控件的这个方法一样,利用SqlDataReader来访问数据库,把检索出来的数据转换成CascadingDropDownNameValue类型,然后进行输出。
不管有多少级下拉框,我们都可以利用这个方法来如法炮制的操作。
完成后,我们就可以设定端点F5一下,欣赏自己的劳动成果了。
Ps:我们可以利用Category属性来完成多个联动下拉菜单在一个方法中获取自己数据。
代码如下:
string[] categoryValues = knownCategoryValues.Split(':', ';');
switch (category)
{
case "city": //定义category为city的那个CascadingDropDown控件响应
string selectCommand = "SELECT * FROM [dbo].[tbCountryRegion] WHERE [RegionType] = 1";
break;
case "Provinces": //定义category为Provinces的那个CascadingDropDown控件响应
string selectCommand = "SELECT * FROM [dbo].[tbCountryRegion] WHERE [RegionType] = 2 AND [RegionID] LIKE '" + categoryValues[1] + "%'";
break;
case "Countries": //定义category为Countries的那个CascadingDropDown控件响应
string selectCommand = "SELECT * FROM [dbo].[tbCountryRegion] WHERE [RegionType] = 3 AND [RegionID] LIKE '" + categoryValues[1] + "%'";
break;
default :
break ;
}
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString);
SqlDataAdapter dbAdaper = new SqlDataAdapter(selectCommand, conn);
DataSet dbset = new DataSet();
dbAdaper.Fill(dbset, "tbCountryRegion");
DataColumn columnRegionName = dbset.Tables["tbCountryRegion"].Columns["RegionName"];
DataColumn columnRegionID = dbset.Tables["tbCountryRegion"].Columns["RegionID"];
List <CascadingDropDownNameValue> values = new List <CascadingDropDownNameValue>();
foreach (DataRow row in dbset.Tables["tbCountryRegion"].Rows)
{
values.Add(new CascadingDropDownNameValue(row[columnRegionName].ToString(), row[columnRegionID].ToString()));
}
return values.ToArray();
}