1.承上启下
2.新增的功能
3.源码
4.小结
承上启下(一些废话,与今天同事的一点对话。小菜:26岁。 同事:30岁。)
上一篇 Asp.net Webform 数据源绑定控件的扩展(懒人的办法):DropDownList
中提到了根据界面属性来动态绑定 DropDownList ,并跟本公司的同事讨论了下,同事的意思是没有必要写控件,原因如下:1. 没有时间写。 2. 后台取读取数据挺方便的(通过硬编码的方式)。一下是小菜跟公司同事的一点点对话,原文如下:
小菜说:现在写了以后一劳永逸。(点评:小菜只是想把封装一下控件的好处阐明一下,希望同事们一起向这方面努力!公司有自己的易用快速开发框架!因为公司的开发环境现在是,硬编码满天飞,没有一个统一的标准!)
同事说:没必要写控件。(点评:小菜很迷惑为什么没有必要,小菜很困惑。)
小菜:为什么没必要,写好了控件。以后业务变更都不需要重新编译,现在每次都要在 Page_Load 里面加载数据,手写代码,如果一旦数据改变,使用 DropDownList 的源码都可能需要更改!
(点评:小菜提出自己的困惑,并通过阐明自己写扩展控件的原因)
同事:不是每次都在 Page_Load 里面加载的?(点评:我想我说的是扩展控件的利弊,不知道为什么同事会提出这个问题?以此做突破口,打败我?)
小菜:不再Page_Load里面加载你数据怎么来?(点评:小菜想了想,感觉无论什么框架,数据在DB也好在文件中也好,肯定得加载到控件端的!小菜接招了!)
同事:你做DropDownList联动的时候,一开始怎么会从DropDownList里面读取呢?(点评:提出假设,同事说的不错。不过小菜想说,我做控件的初衷就是屏蔽代码中的不可控性,提高代码扩展,修改的性能,这种的确是不再Page_Load中加载,但是... ... 大家都明白... ...这一局同事完胜我了,成功了抓住了我语句中的漏洞,我输了!)
小菜:这个我知道但是,这些也要写在cs文件里面啊,也要人为的去写逻辑啊!()(点评:提出者中做法也是有小菜初衷所要解决的问题。)
同事:没必要,你以为开发控件那么容易,根本没时间。(点评:另一个理由,貌似又要回到问题的原点。)
小菜: ... ...(点评:小菜认输了,沉默了... ...)
总结:一些题外话。小菜是个真心喜欢技术的人,对于时间问题小菜想说,每个人都是24个小时,为什么我有时间你没有呢?小菜每天都是1-2点睡觉,7点上班的,下班后回家吃饭,开电脑,然后就是博客园。写代码。睡觉,小菜的技术就这样不是什么高深的东西,也写不出大牛的水平(例如:@Fish Li,我很喜欢他。他的技术都是一针见血的。)但是小菜今年只有26岁,毕业两年,北京工作一年,小菜还很年轻,小菜会一直努力。至于现在我们公司的开发环境来说,我大三的水平时候就能胜任现在的开发任务(就当我是吹牛吧,别拍砖!)。小菜没有浑浑噩噩,也没有放弃对编程的追求。现实的因素左右过我,但是不能决定我。我会一直努力... ... 对于那些只把技术当做混饭吃的工具的人,我不能说你什么!每个人都有自己的选择和处事方法,我只是希望那些真正耐得住寂寞的喜欢编程的人,多交流,小菜向你们多学习。通过自己的志趣,跟自己的生活家庭带来更好的生活。技术,编程,学习不是生活,但也不能这么浑浑噩噩吧?
新增加的功能
对原有功能的扩展,增加了4个新的属性,以此来实现DropDownList的联动功能,支持无限极联动。使用IE 9,Chrome测试过没有问题。
视图例子:
只是做了一个4级联动小例子,不依赖数据库,只依赖我写的数据库操作类,你也可以把数据库操作类自己重写,来实现。
源代码
1 public static Control FindAllControl(this System.Web.UI.Control control, string controlID) 2 { 3 return FindControlForeach(control, controlID); 4 } 5 6 private static Control FindControlForeach(Control control, string controlID) 7 { 8 Control findResult = control.FindControl(controlID); 9 if (findResult == null) 10 { 11 foreach (Control childControl in control.Controls) 12 { 13 findResult = FindControlForeach(childControl, controlID); 14 if (findResult != null) break; 15 } 16 } 17 return findResult; 18 }
由于新增了联动功能,所以需要后台自动识别联动控件的ID所以扩展了 Control 的FindControl 功能。
一下是Page.aspx需要的属性设计(刚才吃着吃着饭,想起来没加!汗!)
1 <div> 2 3 <bsp:DropDownList ID="DropDownList1" runat="server" ConnectionName="Platform" 4 DataTextField="ObjectName" DataValueField="PKey" DefaultText="-全部-" 5 RelevanceID="DropDownList2" SortName="ObjectOrderBy" TableName="RBAC_View" 6 Where="ParentKey is null"> 7 </bsp:DropDownList> 8 <bsp:DropDownList ID="DropDownList2" runat="server" ConnectionName="Platform" 9 DataTextField="ObjectName" DataValueField="UserPKey" DefaultText="-全部-" 10 RelevanceID="DropDownList3" RelevanceName="ParentKey" SortName="ObjectOrderBy" 11 TableName="RBAC_View" Where="PKey=null"> 12 </bsp:DropDownList> 13 <bsp:DropDownList ID="DropDownList3" runat="server" ConnectionName="Platform" 14 DataTextField="UserName" DataValueField="PKey" DefaultText="-请选择-" 15 RelevanceName="PKey" TableName="RBAC_Users" Where="Pkey is null" 16 RelevanceID="DropDownList4"> 17 </bsp:DropDownList> 18 <bsp:DropDownList ID="DropDownList4" runat="server" ConnectionName="Platform" 19 DataTextField="ObjectName" DataValueField="PKey" DefaultText="-请选择-" 20 RelevanceName="UserPkey" SortName="ObjectOrderBy" TableName="RBAC_View" 21 Where="1=2"> 22 </bsp:DropDownList> 23 24 </div>
1 [DefaultProperty("Text")] 2 [ToolboxData("<{0}:DropDownList runat=server></{0}:DropDownList>")] 3 public class DropDownList : System.Web.UI.WebControls.DropDownList 4 { 5 #region Extends Attributes 6 7 private Database DataAccess; 8 9 /// <summary> 10 /// 摘要: 操作数据库的 TableName 11 /// </summary> 12 [Bindable(true)] 13 [Category("Extends")] 14 [DefaultValue("")] 15 [Localizable(true)] 16 public string TableName 17 { 18 get 19 { 20 String s = (String)ViewState["TableName"]; 21 return ((s == null) ? String.Empty : s); 22 } 23 24 set 25 { 26 ViewState["TableName"] = value; 27 } 28 } 29 /// <summary> 30 /// 摘要: 操作数据库的 ConnectionName 31 /// </summary> 32 [Bindable(true)] 33 [Category("Extends")] 34 [DefaultValue("")] 35 [Localizable(true)] 36 public string ConnectionName 37 { 38 get 39 { 40 String s = (String)ViewState["ConnectionName"]; 41 return ((s == null) ? String.Empty : s); 42 } 43 44 set 45 { 46 ViewState["ConnectionName"] = value; 47 } 48 } 49 /// <summary> 50 /// 摘要: DropDownList 默认选项,空则为默认选项 51 /// </summary> 52 [Bindable(true)] 53 [Category("Extends")] 54 [DefaultValue("")] 55 [Localizable(true)] 56 public string DefaultText 57 { 58 get 59 { 60 String s = (String)ViewState["DefaultText"]; 61 return ((s == null) ? String.Empty : s); 62 } 63 64 set 65 { 66 ViewState["DefaultText"] = value; 67 } 68 } 69 /// <summary> 70 /// 摘要: 操作数据库的表的 WHERE 条件 71 /// </summary> 72 [Bindable(true)] 73 [Category("Extends")] 74 [DefaultValue("")] 75 [Localizable(true)] 76 public string Where 77 { 78 get 79 { 80 String s = (String)ViewState["Where"]; 81 return ((s == null) ? "1=1" : s); 82 } 83 84 set 85 { 86 ViewState["Where"] = value; 87 } 88 } 89 /// <summary> 90 /// 摘要: 排序字段,空则为 DataTextField 91 /// </summary> 92 [Bindable(true)] 93 [Category("Extends")] 94 [DefaultValue("")] 95 [Localizable(true)] 96 public string SortName 97 { 98 get 99 { 100 String s = (String)ViewState["SortName"]; 101 return ((s == null) ? this.DataTextField : s); 102 } 103 104 set 105 { 106 ViewState["SortName"] = value; 107 } 108 } 109 /// <summary> 110 /// 摘要: 以此 DataValueFiled 为主的联动 DropDownList.ID 111 /// </summary> 112 [Bindable(true)] 113 [Category("Extends")] 114 [DefaultValue("")] 115 [Localizable(true)] 116 public string RelevanceID 117 { 118 get 119 { 120 String s = (String)ViewState["RelevanceID"]; 121 return ((s == null) ? string.Empty : s); 122 } 123 set 124 { 125 ViewState["RelevanceID"] = value; if (!string.IsNullOrEmpty(value)) { this.AutoPostBack = true; } 126 } 127 } 128 /// <summary> 129 /// 摘要: 接收父级 DropDownList 的值的对应字段 130 /// </summary> 131 [Bindable(true)] 132 [Category("Extends")] 133 [DefaultValue("")] 134 [Localizable(true)] 135 public string RelevanceName 136 { 137 get 138 { 139 String s = (String)ViewState["RelevanceName"]; 140 return ((s == null) ? string.Empty : s); 141 } 142 set 143 { 144 ViewState["RelevanceName"] = value; 145 } 146 } 147 /// <summary> 148 /// 摘要: 是否联动父集 149 /// </summary> 150 [Bindable(true)] 151 [Category("Extends")] 152 [DefaultValue("")] 153 [Localizable(true)] 154 public bool IsRelevanceChild 155 { 156 get 157 { 158 String s = (String)ViewState["RelevanceName"]; 159 return !(s == null); 160 } 161 } 162 /// <summary> 163 /// 摘要: 是否联动子集 164 /// </summary> 165 [Bindable(true)] 166 [Category("Extends")] 167 [DefaultValue("")] 168 [Localizable(true)] 169 public bool IsRelevanceFather 170 { 171 get 172 { 173 String s = (String)ViewState["RelevanceID"]; 174 return !(s == null); 175 } 176 } 177 178 #endregion 179 180 #region Override Method 181 182 protected override void OnDataBinding(EventArgs e) 183 { 184 LoadData(); 185 base.OnDataBinding(e); 186 } 187 188 protected override void OnDataBound(EventArgs e) 189 { 190 base.OnDataBound(e); 191 InsertDefaultText(); 192 RelevanceOther(); 193 194 } 195 196 protected override void OnPagePreLoad(object sender, EventArgs e) 197 { 198 if (!Page.IsPostBack) 199 this.DataBind(); 200 base.OnPagePreLoad(sender, e); 201 } 202 203 protected override void OnSelectedIndexChanged(EventArgs e) 204 { 205 RelevanceOther(); 206 base.OnSelectedIndexChanged(e); 207 } 208 209 #endregion 210 211 #region Private Method 212 213 private void LoadData() 214 { 215 if (!string.IsNullOrEmpty(DataTextField) && !string.IsNullOrEmpty(DataTextField) && !string.IsNullOrEmpty(TableName)) 216 { 217 DataAccess = string.IsNullOrEmpty(ConnectionName) ? 218 (this.Page as Binarysoft.Library.Web.UI.Page).DataAccess : 219 DatabaseFactory.CreateDatabase(ConnectionName); 220 this.DataSource = DataAccess.ExecuteDataTable(string.Format("SELECT {0},{1} FROM {2} WHERE {3} ORDER BY {4}", DataTextField, DataValueField, TableName, Where, SortName)); 221 } 222 } 223 224 private void InsertDefaultText() 225 { 226 if (!string.IsNullOrEmpty(DefaultText)) 227 this.Items.Insert(0, new ListItem(DefaultText, string.Empty)); 228 } 229 230 private void RelevanceOther() 231 { 232 if (IsRelevanceFather) 233 { 234 DropDownList findedControl = (this.Page.Form.FindAllControl(RelevanceID) as DropDownList); 235 if (findedControl != null) 236 { 237 findedControl.Where = string.Format("{0} = '{1}'", findedControl.RelevanceName, this.SelectedValue); 238 findedControl.DataBind(); 239 } 240 } 241 } 242 243 #endregion 244 }
小结
这个控件,没有支持Ajax是我唯一感觉不足的地方。原因是,小菜还没最终决定,如何实现Ajax的功能,以下是小菜的一点想法,实现ajax功能:
1.使用Jquery,但是感觉前台一堆代码要手动维护。
2.使用系统自带的接口,代码有些冗余。
3.使用Anthem的接口,小菜还没有完全弄明白它的原理。
希望,给位大牛给点意见!希望大家同路人多交流,道不同的就不相为谋好了!欢迎拍砖。