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的接口,小菜還沒有完全弄明白它的原理。
希望,給位大牛給點意見!希望大家同路人多交流,道不同的就不相為謀好了!歡迎拍磚。