詳解ASP.NET的Multi-ListBox控件
開(kāi)發(fā)一個(gè)優(yōu)秀的數(shù)據(jù)綁定不是一件很容易的事情。剛開(kāi)始的時(shí)候走了一些彎路,一直緊緊咬著 DataBoundControl類不放。最終失望之后冷靜下來(lái)想到關(guān)于DataSource不就是一個(gè)數(shù)據(jù)集合嗎?明白之后,有關(guān)數(shù)據(jù)源的問(wèn)題基本上也解決了。在整個(gè)ASP.NET Multi-ListBox控件控件開(kāi)發(fā)中,我認(rèn)為最重要的實(shí)際上就是頁(yè)面的生命周期的理解,如果您基本上理解了它的話,那么,基本上,你以后開(kāi)發(fā)一款A(yù)SP.NET控件也不是一件很難的事情。我們還是簡(jiǎn)單了解開(kāi)發(fā)的思路吧。
在ASP.NET Multi-ListBox控件的生命周期中,我們主要需要解決用戶回發(fā)頁(yè)面的時(shí)候保留ListBox的數(shù)據(jù)源(因?yàn)槲覜](méi)有采用復(fù)合控件的方式來(lái)開(kāi)發(fā))。因此,我們需要重寫(xiě)控件的SaveViewState, LoadViewState二個(gè)方法。
- 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 }
為了省事,我沒(méi)有自定義ListItem類,改為直接使用ListItemCollection來(lái)存儲(chǔ)數(shù)據(jù)。因?yàn)镸S沒(méi)有提供ListItemCollection. SaveViewState和LoadViewState,我們必須采用反射的方式來(lái)調(diào)用這二個(gè)方法來(lái)保存數(shù)據(jù)。很讓人郁悶。每當(dāng)?shù)骄o要關(guān)頭,就會(huì)發(fā)現(xiàn)MS寫(xiě)的類,方法不是internal,就是sealed。無(wú)可奈何~當(dāng)然,你也可以自己寫(xiě)一個(gè)類來(lái)代替ListItem類.
我們?cè)陧?yè)面上進(jìn)行ListBox進(jìn)行左移,右移的數(shù)據(jù)全部需要按一定的格式臨時(shí)存儲(chǔ)在HiddenField控件中,這樣我們可以通過(guò)繼承IPostBackDataHandler 接口中的LoadPostData方法獲取我們臨時(shí)存儲(chǔ)的數(shù)據(jù),對(duì)ListBox的數(shù)據(jù)源進(jìn)行添加,移除等操作。
- 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]); 軟件開(kāi)發(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 }
一切就是這么簡(jiǎn)單,就是SaveViewaState,LoadViewState,LoadPostData順序。后面二個(gè)是頁(yè)面回發(fā)的時(shí)候才會(huì)觸發(fā)。只要解決這里,***不過(guò)就是呈現(xiàn)控件而已。 #p#
如果在頁(yè)面中使用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 }
就像前面所說(shuō)那樣,目前只完成的基本的功能,像如果頁(yè)面放了多個(gè)控件之后的問(wèn)題,讓開(kāi)發(fā)人員自定義修改Control Panel的圖標(biāo),自定義JS路徑等都還沒(méi)有考慮完全(時(shí)間有限,只有等以后慢慢完善)。如何跟SqlDataSource控件結(jié)合?如何直接可編輯ListBox的Items屬性就能呈現(xiàn)?呵呵。需要挑戰(zhàn)的還有許多地方。
【編輯推薦】