詳解ASP.NET的Multi-ListBox控件
開發(fā)一個優(yōu)秀的數(shù)據(jù)綁定不是一件很容易的事情。剛開始的時候走了一些彎路,一直緊緊咬著 DataBoundControl類不放。最終失望之后冷靜下來想到關(guān)于DataSource不就是一個數(shù)據(jù)集合嗎?明白之后,有關(guān)數(shù)據(jù)源的問題基本上也解決了。在整個ASP.NET Multi-ListBox控件控件開發(fā)中,我認為最重要的實際上就是頁面的生命周期的理解,如果您基本上理解了它的話,那么,基本上,你以后開發(fā)一款A(yù)SP.NET控件也不是一件很難的事情。我們還是簡單了解開發(fā)的思路吧。
在ASP.NET Multi-ListBox控件的生命周期中,我們主要需要解決用戶回發(fā)頁面的時候保留ListBox的數(shù)據(jù)源(因為我沒有采用復(fù)合控件的方式來開發(fā))。因此,我們需要重寫控件的SaveViewState, LoadViewState二個方法。
- ViewStates
 - 1 protected override void LoadViewState
 - (object savedState)
 - 2 {
 - 3 if (savedState != null)
 - 4 {
 - 5 Triplet triplet = (Triplet)savedState;
 - 6 base.LoadViewState(triplet.First);
 - 7 Reflector.InvokeMethod(this.FirstListBox.
 - Items, "LoadViewState", new object[]
 - { triplet.Second });
 - 8 Reflector.InvokeMethod(this.SecondListBox.Items,
 - "LoadViewState", new object[] { triplet.Third });
 - 9 }
 - 10 else
 - 11 {
 - 12 base.LoadViewState(null);
 - 13 }
 - 14 this._stateLoaded = true;
 - 15 }
 - 16
 - 17 protected override object SaveViewState()
 - 18 {
 - 19 if (EnableViewState == false)
 - 20 return null;
 - 21 //啟用控件視圖狀態(tài)
 - 22 object x = base.SaveViewState();
 - 23 object y = Reflector.InvokeMethod
 - (FirstListBox.Items, "SaveViewState", null);
 - 24 object z = Reflector.InvokeMethod
 - (SecondListBox.Items, "SaveViewState", null);
 - 25 if ((x == null) && (y == null) && (z == null))
 - 26 {
 - 27 return null;
 - 28 }
 - 29 return new Triplet(x, y, z);
 - 30 }
 
為了省事,我沒有自定義ListItem類,改為直接使用ListItemCollection來存儲數(shù)據(jù)。因為MS沒有提供ListItemCollection. SaveViewState和LoadViewState,我們必須采用反射的方式來調(diào)用這二個方法來保存數(shù)據(jù)。很讓人郁悶。每當?shù)骄o要關(guān)頭,就會發(fā)現(xiàn)MS寫的類,方法不是internal,就是sealed。無可奈何~當然,你也可以自己寫一個類來代替ListItem類.
我們在頁面上進行ListBox進行左移,右移的數(shù)據(jù)全部需要按一定的格式臨時存儲在HiddenField控件中,這樣我們可以通過繼承IPostBackDataHandler 接口中的LoadPostData方法獲取我們臨時存儲的數(shù)據(jù),對ListBox的數(shù)據(jù)源進行添加,移除等操作。
- IPostBackDataHandler
 - 1 public bool LoadPostData
 - (string postDataKey, NameVal
 - ueCollection postCollection)
 - 2 {
 - 3 bool resultValueFlag = false;
 - 4 //移除指定ListItem,
 - 并需要添加了Left ListBox列表框中
 - 5 string itemsRemoved =
 - postCollection[this.ClientID "_REMOVED"];
 - 6 string[] itemsRemovedCol =
 - itemsRemoved.Split(',');
 - 7 if (itemsRemovedCol != null)
 - 8 {
 - 9 if (itemsRemovedCol.Length 〉
 - 0 && itemsRemovedCol[0] != "")
 - 10 {
 - 11 for (int i = 0; i 〈
 - itemsRemovedCol.Length; i )
 - 12 {
 - 13 string[] itemsRemoveItems =
 - itemsRemovedCol[i].Split('|');
 - 14 ListItem item = this.SecondListBox.
 - Items.FindByValue(itemsRemoveItems[1]);
 - 15 if (item != null)
 - 16 {
 - 17 this.SecondListBox.Items.Remove(item);
 - 18 }
 - 19 item = this.FirstListBox.Items.
 - FindByValue(itemsRemoveItems[1]);
 - 20 if (item == null)
 - 21 {
 - 22
 - 23 this.FirstListBox.Items.Add
 - (new ListItem(itemsRemoveItems[0],
 - itemsRemoveItems[1]));
 - 24 }
 - 25 resultValueFlag = true;
 - 26 }
 - 27 }
 - 28 }
 - 29 //從客戶端添加指定的ListItem
 - 30 string itemsAdded = postCollection
 - [this.ClientID "_ADDED"];
 - 31 string[] itemsAddedCol = itemsAdded.
 - Split(',');
 - 32 if (itemsAddedCol != null)
 - 33 {
 - 34 if (itemsAddedCol.Length 〉
 - 0 && itemsAddedCol[0] != "")
 - 35 {
 - 36 int counter = -1;
 - 37 for (int i = 0; i 〈
 - itemsAddedCol.Length; i )
 - 38 {
 - 39 string[] itemsAddItems =
 - itemsAddedCol[i].Split('|');
 - 40 ListItem item = this.SecondListBox.
 - Items.FindByValue(itemsAddItems[1]);
 - 41 if (item == null)
 - 42 {
 - 43 this.SecondListBox.Items.Add(new
 - ListItem(itemsAddItems[0],itemsAddItems[1]));
 - 44 counter = 1;
 - 45 }
 - 46 item = this.FirstListBox.Items.
 - FindByValue(itemsAddItems[1]); 軟件開發(fā)網(wǎng) www.mscto.com
 - 47 if (item != null)
 - 48 {
 - 49 this.FirstListBox.Items.Remove(item);
 - 50 }
 - 51 }
 - 52 resultValueFlag = counter 〉 -1 ? true : false;
 - 53 }
 - 54 }
 - 55
 - 56 //從客戶端中移除指定的ListItem
 - 57 return resultValueFlag;
 - 58 }
 - 59
 - 60 public void RaisePostDataChangedEvent()
 - 61 {
 - 62 //TODO::
 - 63 }
 
一切就是這么簡單,就是SaveViewaState,LoadViewState,LoadPostData順序。后面二個是頁面回發(fā)的時候才會觸發(fā)。只要解決這里,***不過就是呈現(xiàn)控件而已。 #p#
如果在頁面中使用ASP.NET Multi-ListBox控件?
- HTML
 - 1〈asp:MultiListBox ID="ListBox1"
 - runat="server" Rows="10" Width="250px"
 - Height="200px" DataTextField="UserName"
 - DataValueField="UserID"
 - SelectionMode="Multiple" 〉
 - 2 〈FirstListBox 〉
 - 〈StyleSheet Width="100px" / 〉
 - 〈/FirstListBox 〉
 - 3 〈SecondListBox 〉
 - 〈StyleSheet Width="100px" / 〉
 - 〈/SecondListBox 〉
 - 4 〈/asp:MultiListBox 〉
 - 5
 - Submit
 - 1protected void Page_Load
 - (object sender, EventArgs e)
 - 2 {
 - 3 if (Page.IsPostBack)
 - 4 return;
 - 5 ListBox1.FirstListBox.
 - DataSource = LoadData(1, 5);
 - 6 ListBox1.SecondListBox.DataSource =
 - LoadData(6, 10);
 - 7 ListBox1.DataBind();
 - 8}
 - 9protected void Button1_Click(object
 - sender, EventArgs e)
 - 10 {
 - 11 Response.Write("您SecondList選擇的值為:
 - 〈br/ 〉");
 - 12 foreach (ListItem item in this.ListBox1.
 - SecondListBox.Items)
 - 13 {
 - 14 Response.Write(item.Text ":" item.Value
 - "〈br/ 〉");
 - 15 }
 - 16 Response.Write("您FirstList選擇的值為:
 - 〈br/ 〉");
 - 17 foreach (ListItem item in this.ListBox1.
 - FirstListBox.Items)
 - 18 {
 - 19 Response.Write(item.Text ":" item.Value
 - "〈br/ 〉");
 - 20 }
 - 21 }
 
就像前面所說那樣,目前只完成的基本的功能,像如果頁面放了多個控件之后的問題,讓開發(fā)人員自定義修改Control Panel的圖標,自定義JS路徑等都還沒有考慮完全(時間有限,只有等以后慢慢完善)。如何跟SqlDataSource控件結(jié)合?如何直接可編輯ListBox的Items屬性就能呈現(xiàn)?呵呵。需要挑戰(zhàn)的還有許多地方。
【編輯推薦】















 
 
 
 
 
 
 