你的联动够快够小吗——基于Telerik(ASP.NET平台)
2013-12-12 11:09 y-z-f 阅读(1151) 评论(0) 编辑 收藏 举报一、目的
这篇文章主要是以如何实现联动下拉为核心,其要原理是利用两个下拉控件。默认两个下拉均为未选择状态,并且
父下拉中存在数据,子下来中没有数据。只有当用户选择某一个父下拉中的某条数据后,子下拉中才会显示所选父数据
的子数据。
注:使用的控件是基于telerik,如果你尚未安装请下载安装
二、实现
1.我们新建一个空的ASP.NET网站项目,并且在其中新建一个LinkageDropDown的Web页面,并添加一个App_
Code文件夹,在文件夹中新建一个名为DataModel的类文件。并且点击该文件,将生成操作改成编译,结果如图1.1。
图 1.1
2.在DataModel中创建模拟数据,代码如下
1 public class DataModels 2 { 3 private DataTable table1 = new DataTable(); 4 private DataTable table2 = new DataTable(); 5 6 public DataModels() 7 { 8 table1.Columns.Add("id"); 9 table1.Columns.Add("name"); 10 11 table2.Columns.Add("id"); 12 table2.Columns.Add("name"); 13 table2.Columns.Add("bid"); 14 15 AddData(); 16 } 17 18 protected void AddData() 19 { 20 DataRow dr = table1.NewRow(); 21 dr["id"] = "1"; 22 dr["name"] = "大类一"; 23 table1.Rows.Add(dr); 24 25 dr = table1.NewRow(); 26 dr["id"] = "2"; 27 dr["name"] = "大类二"; 28 table1.Rows.Add(dr); 29 30 dr = table1.NewRow(); 31 dr["id"] = "3"; 32 dr["name"] = "大类三"; 33 table1.Rows.Add(dr); 34 35 dr = table1.NewRow(); 36 dr["id"] = "4"; 37 dr["name"] = "大类四"; 38 table1.Rows.Add(dr); 39 40 dr = table1.NewRow(); 41 dr["id"] = "5"; 42 dr["name"] = "大类五"; 43 table1.Rows.Add(dr); 44 45 dr = table1.NewRow(); 46 dr["id"] = "6"; 47 dr["name"] = "大类六笑嘻嘻笑嘻嘻系"; 48 table1.Rows.Add(dr); 49 50 dr = table2.NewRow(); 51 dr["id"] = "1"; 52 dr["name"] = "大类一的小类一"; 53 dr["bid"] = "1"; 54 table2.Rows.Add(dr); 55 56 dr = table2.NewRow(); 57 dr["id"] = "1"; 58 dr["name"] = "大类一的小类二"; 59 dr["bid"] = "1"; 60 table2.Rows.Add(dr); 61 62 dr = table2.NewRow(); 63 dr["id"] = "1"; 64 dr["name"] = "大类二的小类一"; 65 dr["bid"] = "2"; 66 table2.Rows.Add(dr); 67 68 dr = table2.NewRow(); 69 dr["id"] = "1"; 70 dr["name"] = "大类二的小类二"; 71 dr["bid"] = "2"; 72 table2.Rows.Add(dr); 73 74 dr = table2.NewRow(); 75 dr["id"] = "1"; 76 dr["name"] = "大类三的小类一"; 77 dr["bid"] = "3"; 78 table2.Rows.Add(dr); 79 80 dr = table2.NewRow(); 81 dr["id"] = "1"; 82 dr["name"] = "大类三的小类二"; 83 dr["bid"] = "3"; 84 table2.Rows.Add(dr); 85 86 } 87 88 public DataTable GetTable1() 89 { 90 return table1; 91 } 92 93 public DataTable GetTable2() 94 { 95 return table2; 96 }
其中GetTable1返回大类的数据,GetTable2返回小类的数据。
3.在LinkageDropDown.aspx中拖放控件,最终代码如下:
1 <form id="form1" runat="server"> 2 <telerik:RadScriptManager ID="RadScriptManager1" runat="server"></telerik:RadScriptManager> 3 <telerik:RadAjaxManager ID="RadAjaxManager1" runat="server"> 4 <AjaxSettings> 5 <telerik:AjaxSetting AjaxControlID="RadDropDownList1"> 6 <UpdatedControls> 7 <telerik:AjaxUpdatedControl ControlID="RadDropDownList2" /> 8 </UpdatedControls> 9 </telerik:AjaxSetting> 10 </AjaxSettings> 11 </telerik:RadAjaxManager> 12 <div style="width:100%;float:left;"> 13 <div style="width: 150px; float: left; overflow: hidden;"> 14 <telerik:RadDropDownList ValidationGroup="linkage" Width="150" AutoPostBack="true" DataTextField="name" DataValueField="id" ID="RadDropDownList1" runat="server" DefaultMessage="请选择大类" EnableAjaxSkinRendering="False" EnableViewState="False" OnSelectedIndexChanged="RadDropDownList1_SelectedIndexChanged" EnableEmbeddedBaseStylesheet="False" EnableEmbeddedScripts="False" EnableEmbeddedSkins="False" EnableTheming="False" Skin="MetroTouch"></telerik:RadDropDownList> 15 </div> 16 <div style="width: 150px; float: left; overflow: hidden; margin-left: 35px;"> 17 <telerik:RadDropDownList ValidationGroup="linkage" Width="150" ID="RadDropDownList2" DataTextField="name" DataValueField="id" runat="server" DefaultMessage="请选择小类" EnableViewState="False" Skin="MetroTouch"></telerik:RadDropDownList> 18 </div> 19 </div> 20 <div> 21 <telerik:RadButton ID="RadButton1" ValidationGroup="linkage" CausesValidation="true" runat="server" Text="提交" Skin="MetroTouch" OnClick="RadButton1_Click"></telerik:RadButton> 22 </div> 23 </form>
其中需要重点说明的是父下拉控件的AutoPostBack必须手动设置为true,否则ajax下可能会无法触发后台事件。这里我们采用了
DefaultMessage属性用来这是没有选择时显示的信息,我相信很多人都会采用在DataTable插入一条数据,用来显示默认选择的状态,
或者把DataTable循环一遍,用创建子控件的方式一个一个添加进去。而这里我们没有这么做,而是直接将DataTable数据源绑定到控
件上去的。首先我们可以看到DataTextField属性以及DataValueField属性,分为表示将表中的哪一个字段的数据作为下拉显示的文本
以及作为选择后的值。
这里还有一点很重要,就是视图的大小,一个RadDropDownList控件默认情况下,会根据你需要显示的数据扩大ViewState。
这里我们仅仅只显示的几条,但是视图的却比原本增加了2行左右,是相当的庞大。所以这里我们干脆直接禁用了这两个下拉的视图
状态。可能你会想这样会造成什么后果,这里我们假设下你的做法,如果你只会在第一次才给下拉控件加载数据,并且在提交页面之
后不在加载数据给下拉控件,那么在不使用视图下你会看到当你点击提交之后,下拉中除了你所选的数据,其他的数据都不会存在了,
如果是聪明的人应该立即就能反应过来为什么我说视图的大小是根据你的数据大小,因为控件会把你的数据保存在视图中,当你点击
提交之后,控件会自动的从视图中读取你给这个控件加载的数据,重新加载。所以你就可以看到在你点击提交之后,触发后台的事件,
但是没有给这个控件绑定数据,然而在页面控件依然可以看到数据还是存在。我们禁用了视图是因为我们全过程采用的是ajax,所以
不会存在上述的问题,即我们可以禁用视图状态。
4.下面是后台代码
1 public partial class LinkageDropdown : System.Web.UI.Page 2 { 3 protected void Page_Load(object sender, EventArgs e) 4 { 5 if (!IsPostBack) 6 { 7 BindDropDown(); 8 } 9 } 10 11 protected void BindParentDropDown(DataTable data, String selid) 12 { 13 RadDropDownList1.DataSource = data; 14 RadDropDownList1.DataBind(); 15 RadDropDownList1.SelectedValue = selid; 16 if ("0".Equals(selid)) 17 { 18 RadDropDownList1.SelectedIndex = -1; 19 } 20 } 21 22 protected void BindChildDropDown(DataTable data, String selid) 23 { 24 RadDropDownList2.DataSource = data; 25 RadDropDownList2.DataBind(); 26 RadDropDownList2.SelectedValue = selid; 27 if ("0".Equals(selid)) 28 { 29 RadDropDownList2.SelectedIndex = -1; 30 } 31 } 32 33 protected void BindDropDown(string parvalue = "0",string childvalue = "0") 34 { 35 DataModels dm = new DataModels(); 36 BindParentDropDown(dm.GetTable1(),parvalue); 37 if (String.IsNullOrEmpty(childvalue)) 38 { 39 BindParentDropDown(dm.GetTable2(), childvalue); 40 } 41 } 42 43 protected void RadDropDownList1_SelectedIndexChanged(object sender, Telerik.Web.UI.DropDownListEventArgs e) 44 { 45 DataModels dm = new DataModels(); 46 var table = dm.GetTable2().AsEnumerable().Where(x => x["bid"].Equals(e.Value) ).Select(x => x); 47 if (table.Count() > 0) 48 { 49 BindChildDropDown(table.CopyToDataTable(),"0"); 50 } 51 } 52 53 protected void RadButton1_Click(object sender, EventArgs e) 54 { 55 if (Page.IsValid) 56 { 57 Response.Write("the parent id is " + RadDropDownList1.SelectedValue + ",text is " + RadDropDownList1.SelectedText + "<br />"); 58 Response.Write("the child id is " + RadDropDownList2.SelectedValue + ",text is " + RadDropDownList2.SelectedText + "<br />"); 59 } 60 } 61 }
这里可以看到我的做法是只有第一次进到页面之后才会给控件加载数据,并且我仅仅只是加载了父下拉控件的数据,并没有加载子下拉控件的
数据,但是这里我却绑定了父控件的 SelectedIndexChanged 事件,同时这个事件的触发是采用ajax无刷新技术。其中可以看到这段代码:
var table = dm.GetTable2().AsEnumerable().Where(x => x["bid"].Equals(e.Value) ).Select(x => x);
这里我采用了lambda表示的方法,从子类表中查找那属于父类的子类数据,然后再通过CopyToDataTable转换成DataTable,这样才可以绑定
数据源。同时还要注意这里要判断存不存在数据,如果在不存在数据的情况下调用CopyToDataTable将会导致抛出异常。
然后我们看看两个下拉控件绑定数据源的地方:
1 protected void BindParentDropDown(DataTable data, String selid) 2 { 3 RadDropDownList1.DataSource = data; 4 RadDropDownList1.DataBind(); 5 RadDropDownList1.SelectedValue = selid; 6 if ("0".Equals(selid)) 7 { 8 RadDropDownList1.SelectedIndex = -1; 9 } 10 }
重点是SelectedValue属性,因为在日常的开发中,我们有时需要在显示下拉的同时还要能够设置一个选项,但是我们只知道所选项的值,根本
无法判断所处的索引,所以这里我们就可以通过SelectedValue属性设置所选项的值,如果你设置的值不存在也不会导致异常。这里还要提及的一点
就是SelectedIndex,你可能会疑惑既然我们不知道索引为什么这里要赋为-1,其实这个主要是解决RadDropDownList控件中的一个Bug,当我们
选择一个大类,又选择了一个小类之后。我们改变所选大类,按道理小类应该是恢复未选择状态,但是我们实际发现子下拉控件会按照索引继续选择
新的小类中的数据,所以这里我们需要手动设置为-1,以恢复未选择状态。
5.最终效果图如下:
一进到页面:
选择一个大类:
选择一个小类:
改变大类:
点击提交: