為避免多個 EnhancedListBox 重複輸出 JS,於 OnInit 使用 Page.ClientScript.RegisterClientScriptBlock 註冊共用函式 MoveItemUp、MoveItemDown、BuildItemList (序列化列表內容至隱藏欄位)。
protected override void OnInit(EventArgs e) {
base.OnInit(e);
if (!Page.ClientScript.IsClientScriptBlockRegistered("EnhancedListBoxScripts")) {
StringBuilder sb = new StringBuilder();
sb.Append(@"
function MoveItemUp(selectElem) { ... }
function MoveItemDown(selectElem) { ... }
function BuildItemList(selectElem, hiddenField) {
// 將 select 所有 option 序列化為 'value1,text1|value2,text2|...' 存入 hiddenField.value
}");
Page.ClientScript.RegisterClientScriptBlock(typeof(EnhancedListBox), "EnhancedListBoxScripts", sb.ToString(), true);
}
}
渲染按鈕時使用 AddAttribute 堆疊 onclick:
string upScript = "MoveItemUp(document.all.'" + ClientID + "'); BuildItemList(document.all.'" + ClientID + "', document.all.__" + ClientID + ");";
output.AddAttribute(HtmlTextWriterAttribute.Onclick, upScript);
隱藏欄位於 OnPreRender 註冊:Page.ClientScript.RegisterHiddenField("__" + ID, "")。
繼承 IPostBackDataHandler,覆寫 LoadPostData 解析隱藏欄位序列化字串,重建 Items 集合順序,回傳 true 通知 ASP.NET 引發 TextChanged 等事件:
public bool LoadPostData(string postDataKey, NameValueCollection postCollection) {
string serialized = postCollection["__" + ID];
if (!string.IsNullOrEmpty(serialized)) {
Items.Clear();
foreach (string pair in serialized.Split('|')) {
string[] parts = pair.Split(',');
Items.Add(new ListItem(parts[1], parts[0]));
}
return true; // 項目順序已變更
}
return false;
}
繼承 CompositeControl,CreateChildControls 建立兩個 EnhancedListBox (SourceList、TargetList) 與四個按鈕 (▶、◀、▶▶、◀◀),處理按鈕 Click 事件在伺服器端移動 ListItem,ViewState 自動保持雙邊狀態。