增強DropDownList和ListBox控件:保持客戶端腳本添加的options
導讀:
DropDownList、ListBox由於Items是保存在ViewState中,回傳後服務端會從ViewState恢復所有Items,所以,客戶端對options的設置在回傳後無法獲取、保持。
一個解決思路是通過在頁面Submit的時候,在客戶端解碼viewstate,找出相應items集合,根據客戶端對該集合的處理,進行重新設置,然後再把更改過的viewstate重新編碼提交。由於一個頁面的viewstate可以是非常之大,所以這個操作在客戶端的壓力可能會較大。
另一個思路是將客戶端對options的變更保存到隱藏域中提交,然後服務端根據該隱藏域的信息重建ListControl的items。相對而言,該實現效率更高。這個解決方案就是基於該思路來做的。我繼承DropDownList、ListBox,讓每個控件實例與一個隱藏域一起輸出到客戶端,在客戶端Form.onsubmit事件時,通過腳本把客戶對該Select控件所包含options的變更,以xml保存到隱藏域。然後在控件的處理CreateChildControls事件時,分析該隱藏域的內容,解析並創建出各ListItem。
以下是解決方案結構圖:
在ClientOptionsHolder項目裏,ClientOptionsHolder.js包含把options存入隱藏域的客戶端腳本。代碼如下:
function GetAttributes_BB49C217_C465_4163_97D6_69568B71A502(oElem)
{
var oAttribs = oElem.attributes;
var s = ""
for (var i = 0 i < oAttribs.length; i++) <br >
{
var oAttrib = oAttribs[i];
if(oAttrib.specified && oAttrib.nodeName!='selected')
s += ' ' + oAttrib.nodeName + '="' + oAttrib.nodeValue + '"';
}
if(oAttribs.getNamedItem("selected").value == 'true')
s += ' selected="true"';
return s;
}
function StoreClientOptions_BB49C217_C465_4163_97D6_69568B71A502(oSelect,oHidden)
{
oHidden.value = ""
for(i=0i
{
oOption = oSelect.options[i];
attrs = GetAttributes_BB49C217_C465_4163_97D6_69568B71A502(oOption);
oHidden.value +='
}
oHidden.value += "items>"
oHidden.value=escape(oHidden.value);
}
第一個函數是用來獲取各個option的屬性集合。只有明確設定了的屬性(通過Attribute.specified判斷)以及opton的select屬性是true時,才添加到集合中。
第二個函數的作用是把指定Select的options以被escape編碼的xml的格式放入對應隱藏域。
繼承的DropDownList代碼如下,非常簡單:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
namespace ZiffWong.Exercise.ControlLibrary
{
public class DropDownList : System.Web.UI.WebControls.DropDownList
{
ClientOptionsHolder _StateHolder;
public DropDownList()
: base()
{
_StateHolder = new ClientOptionsHolder(this);
}
protected override void CreateChildControls()
{
if (!Page.IsPostBack || !this.EnableViewState)
base.CreateChildControls();
else
_StateHolder.SetItemsForPostBack();
}
}
}
它在初始化的時候指定了一個ClientOptionsHolder,將自身作爲參數傳遞給它;然後在CreateChildControls時,判斷到當前頁面狀態如果是從客戶端回傳時,則讓ClientOptionsHolder的SetItemsForPostBack()來處理Items的生成。可見,控件能夠保存客戶端設置的細節,是由ClientOptionsHolder來實現的。下面來看這個ClientOptionsHolder的具體實現:
ClientOptionsHolder.cs 1
using System; 2
using System.Collections.Generic; 3
using System.Text; 4
using System.Web.UI.WebControls; 5
using System.Web; 6
using System.Web.UI; 7
using System.Xml; 8
9
namespace ZiffWong.Exercise.ControlLibrary10
{11
/**////
12
/// Hodes options from client.13
///
14
public class ClientOptionsHolder15
{16
const string GUID = "BB49C217_C465_4163_97D6_69568B71A502"
17
string SETHIDDENFILED_FUNCTONNAME = "StoreClientOptions_" + GUID;18
Type myType = typeof(ClientOptionsHolder);19
ListControl controlToHold;20
21
string HIDDEN_FIELD_KEY22
{23
get
24
{25
return controlToHold.ClientID + "_MemField"
26
}
27
}
28
29
public ClientOptionsHolder(ListControl control)30
{31
this.controlToHold = control;32
controlToHold.PreRender += new EventHandler(control_PreRender);33
}
34
35
public void SetItemsForPostBack()36
{37
if (!controlToHold.Page.IsPostBack)38
return
39
40
XmlDocument doc = new XmlDocument();41
doc.LoadXml(HttpContext.Current.Server.UrlDecode(HttpContext.Current.Request.Form[HIDDEN_FIELD_KEY]));42
XmlNodeList nodes = doc.SelectNodes("/items/item");43
44
controlToHold.Items.Clear();45
foreach (XmlNode node in nodes)46
{47
// Set text and value.
48
string itemValue;49
string itemText;50
itemText = node.Attributes["text"] == null ? null : node.Attributes["text"].InnerText;51
itemValue = node.Attributes["value"] == null ? null : node.Attributes["value"].InnerText;52
ListItem li = new ListItem(itemText, itemValue);53
54
//Set selected.
55
if (node.Attributes["selected"] != null && node.Attributes["selected"].Value == "true")56
li.Selected = true
57
58
/**/////Those ListItems with "Enabled"==false will not be added to items collection because they will not render any outputs.
59
//if (node.Attributes["disabled"] != null)60
//li.Enabled = false;61
62
//Apply other attributes such as "label","isMultiLine" etc.
63
foreach (XmlAttribute attr in node.Attributes)64
{65
string attrName = attr.Name;66
if (attrName != "text" && attrName != "value" && attrName != "selected")67
{68
li.Attributes.Add(attrName, attr.Value);69
}
70
}
71
72
controlToHold.Items.Add(li);73
}
74
}
75
76
void control_PreRender(object sender, EventArgs e)77
{78
string senderClientID = ((ListControl)sender).ClientID;79
Control control = (Control)sender;80
string onSubmitScriptKey = string.Format("SetHiddenField_{0}", senderClientID);81
if (!control.Page.ClientScript.IsOnSubmitStatementRegistered(myType, onSubmitScriptKey))82
{83
control.Page.ClientScript.RegisterClientScriptResource(myType, "ZiffWong.Exercise.ControlLibrary.ClientOptionsHolders.js");84
85
string scriptBody = SETHIDDENFILED_FUNCTONNAME + string.Format("(document.all.{0},document.all.{1});", senderClientID, HIDDEN_FIELD_KEY);86
control.Page.ClientScript.RegisterOnSubmitStatement(myType, onSubmitScriptKey, scriptBody);87
control.Page.ClientScript.RegisterClientScriptBlock(myType, HIDDEN_FIELD_KEY, string.Format(""hidden/" id=/"
{0}/" name=/"
{0}/"/>", HIDDEN_FIELD_KEY));88
89
}
90
}
91
}
92
}
93
它的初始化函數中把傳入的ListControl的PreRender事件掛接control_PreRender 函數,該函數首先把上面的Javascript資源鏈接註冊到頁面,然後在客戶端的OnSubmit中添加對保存options到隱藏域的JS函數的調用。最後,把隱藏域輸出到客戶端。
SetItemsForPostBack()由掛接該ClientOptionsHolder的ListControl在CreateChildControls時調用。它解析客戶端隱藏域裏面的xml,據此生成所有Items集合。
爲了能夠使用dll內嵌的資源文件,需要在AssemblyInfo.cs中做如下設置:
[assembly: System.Web.UI.TagPrefix("ZiffWong.Exercise.ControlLibrary", "mstc")]
[assembly: System.Web.UI.WebResource("ZiffWong.Exercise.ControlLibrary.ClientOptionsHolders.js", "application/x-javascript")]
注意在資源文件ClientOptionsHolders.js前需要加上該控件所在程序集的默認命名空間。程序中對該資源的引用也需要如此處理。
對ListBox的處理和DropDownList一樣:
ListBox.csCode highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
namespace ZiffWong.Exercise.ControlLibrary
{
public class ListBox : System.Web.UI.WebControls.ListBox
{
ClientOptionsHolder _StateHolder;
public ListBox()
: base()
{
_StateHolder = new ClientOptionsHolder(this);
}
protected override void CreateChildControls()
{
if (!Page.IsPostBack || !this.EnableViewState)
base.CreateChildControls();
else
_StateHolder.SetItemsForPostBack();
}
}
}
本文轉自
http://www.cnblogs.com/meil/archive/2006/10/19/533838.html
DropDownList、ListBox由於Items是保存在ViewState中,回傳後服務端會從ViewState恢復所有Items,所以,客戶端對options的設置在回傳後無法獲取、保持。
一個解決思路是通過在頁面Submit的時候,在客戶端解碼viewstate,找出相應items集合,根據客戶端對該集合的處理,進行重新設置,然後再把更改過的viewstate重新編碼提交。由於一個頁面的viewstate可以是非常之大,所以這個操作在客戶端的壓力可能會較大。
另一個思路是將客戶端對options的變更保存到隱藏域中提交,然後服務端根據該隱藏域的信息重建ListControl的items。相對而言,該實現效率更高。這個解決方案就是基於該思路來做的。我繼承DropDownList、ListBox,讓每個控件實例與一個隱藏域一起輸出到客戶端,在客戶端Form.onsubmit事件時,通過腳本把客戶對該Select控件所包含options的變更,以xml保存到隱藏域。然後在控件的處理CreateChildControls事件時,分析該隱藏域的內容,解析並創建出各ListItem。
以下是解決方案結構圖:
在ClientOptionsHolder項目裏,ClientOptionsHolder.js包含把options存入隱藏域的客戶端腳本。代碼如下:
function GetAttributes_BB49C217_C465_4163_97D6_69568B71A502(oElem)
{
var oAttribs = oElem.attributes;
var s = ""
for (var i = 0 i < oAttribs.length; i++) <br >
{
var oAttrib = oAttribs[i];
if(oAttrib.specified && oAttrib.nodeName!='selected')
s += ' ' + oAttrib.nodeName + '="' + oAttrib.nodeValue + '"';
}
if(oAttribs.getNamedItem("selected").value == 'true')
s += ' selected="true"';
return s;
}
function StoreClientOptions_BB49C217_C465_4163_97D6_69568B71A502(oSelect,oHidden)
{
oHidden.value = ""
for(i=0i
{
oOption = oSelect.options[i];
attrs = GetAttributes_BB49C217_C465_4163_97D6_69568B71A502(oOption);
oHidden.value +='
}
oHidden.value += "items>"
oHidden.value=escape(oHidden.value);
}
第一個函數是用來獲取各個option的屬性集合。只有明確設定了的屬性(通過Attribute.specified判斷)以及opton的select屬性是true時,才添加到集合中。
第二個函數的作用是把指定Select的options以被escape編碼的xml的格式放入對應隱藏域。
繼承的DropDownList代碼如下,非常簡單:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
namespace ZiffWong.Exercise.ControlLibrary
{
public class DropDownList : System.Web.UI.WebControls.DropDownList
{
ClientOptionsHolder _StateHolder;
public DropDownList()
: base()
{
_StateHolder = new ClientOptionsHolder(this);
}
protected override void CreateChildControls()
{
if (!Page.IsPostBack || !this.EnableViewState)
base.CreateChildControls();
else
_StateHolder.SetItemsForPostBack();
}
}
}
它在初始化的時候指定了一個ClientOptionsHolder,將自身作爲參數傳遞給它;然後在CreateChildControls時,判斷到當前頁面狀態如果是從客戶端回傳時,則讓ClientOptionsHolder的SetItemsForPostBack()來處理Items的生成。可見,控件能夠保存客戶端設置的細節,是由ClientOptionsHolder來實現的。下面來看這個ClientOptionsHolder的具體實現:
ClientOptionsHolder.cs 1
using System; 2
using System.Collections.Generic; 3
using System.Text; 4
using System.Web.UI.WebControls; 5
using System.Web; 6
using System.Web.UI; 7
using System.Xml; 8
9
namespace ZiffWong.Exercise.ControlLibrary10
{11
/**////
12
/// Hodes options from client.13
///
14
public class ClientOptionsHolder15
{16
const string GUID = "BB49C217_C465_4163_97D6_69568B71A502"
17
string SETHIDDENFILED_FUNCTONNAME = "StoreClientOptions_" + GUID;18
Type myType = typeof(ClientOptionsHolder);19
ListControl controlToHold;20
21
string HIDDEN_FIELD_KEY22
{23
get
24
{25
return controlToHold.ClientID + "_MemField"
26
}
27
}
28
29
public ClientOptionsHolder(ListControl control)30
{31
this.controlToHold = control;32
controlToHold.PreRender += new EventHandler(control_PreRender);33
}
34
35
public void SetItemsForPostBack()36
{37
if (!controlToHold.Page.IsPostBack)38
return
39
40
XmlDocument doc = new XmlDocument();41
doc.LoadXml(HttpContext.Current.Server.UrlDecode(HttpContext.Current.Request.Form[HIDDEN_FIELD_KEY]));42
XmlNodeList nodes = doc.SelectNodes("/items/item");43
44
controlToHold.Items.Clear();45
foreach (XmlNode node in nodes)46
{47
// Set text and value.
48
string itemValue;49
string itemText;50
itemText = node.Attributes["text"] == null ? null : node.Attributes["text"].InnerText;51
itemValue = node.Attributes["value"] == null ? null : node.Attributes["value"].InnerText;52
ListItem li = new ListItem(itemText, itemValue);53
54
//Set selected.
55
if (node.Attributes["selected"] != null && node.Attributes["selected"].Value == "true")56
li.Selected = true
57
58
/**/////Those ListItems with "Enabled"==false will not be added to items collection because they will not render any outputs.
59
//if (node.Attributes["disabled"] != null)60
//li.Enabled = false;61
62
//Apply other attributes such as "label","isMultiLine" etc.
63
foreach (XmlAttribute attr in node.Attributes)64
{65
string attrName = attr.Name;66
if (attrName != "text" && attrName != "value" && attrName != "selected")67
{68
li.Attributes.Add(attrName, attr.Value);69
}
70
}
71
72
controlToHold.Items.Add(li);73
}
74
}
75
76
void control_PreRender(object sender, EventArgs e)77
{78
string senderClientID = ((ListControl)sender).ClientID;79
Control control = (Control)sender;80
string onSubmitScriptKey = string.Format("SetHiddenField_{0}", senderClientID);81
if (!control.Page.ClientScript.IsOnSubmitStatementRegistered(myType, onSubmitScriptKey))82
{83
control.Page.ClientScript.RegisterClientScriptResource(myType, "ZiffWong.Exercise.ControlLibrary.ClientOptionsHolders.js");84
85
string scriptBody = SETHIDDENFILED_FUNCTONNAME + string.Format("(document.all.{0},document.all.{1});", senderClientID, HIDDEN_FIELD_KEY);86
control.Page.ClientScript.RegisterOnSubmitStatement(myType, onSubmitScriptKey, scriptBody);87
control.Page.ClientScript.RegisterClientScriptBlock(myType, HIDDEN_FIELD_KEY, string.Format(""hidden/" id=/"
{0}/" name=/"
{0}/"/>", HIDDEN_FIELD_KEY));88
89
}
90
}
91
}
92
}
93
它的初始化函數中把傳入的ListControl的PreRender事件掛接control_PreRender 函數,該函數首先把上面的Javascript資源鏈接註冊到頁面,然後在客戶端的OnSubmit中添加對保存options到隱藏域的JS函數的調用。最後,把隱藏域輸出到客戶端。
SetItemsForPostBack()由掛接該ClientOptionsHolder的ListControl在CreateChildControls時調用。它解析客戶端隱藏域裏面的xml,據此生成所有Items集合。
爲了能夠使用dll內嵌的資源文件,需要在AssemblyInfo.cs中做如下設置:
[assembly: System.Web.UI.TagPrefix("ZiffWong.Exercise.ControlLibrary", "mstc")]
[assembly: System.Web.UI.WebResource("ZiffWong.Exercise.ControlLibrary.ClientOptionsHolders.js", "application/x-javascript")]
注意在資源文件ClientOptionsHolders.js前需要加上該控件所在程序集的默認命名空間。程序中對該資源的引用也需要如此處理。
對ListBox的處理和DropDownList一樣:
ListBox.csCode highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
namespace ZiffWong.Exercise.ControlLibrary
{
public class ListBox : System.Web.UI.WebControls.ListBox
{
ClientOptionsHolder _StateHolder;
public ListBox()
: base()
{
_StateHolder = new ClientOptionsHolder(this);
}
protected override void CreateChildControls()
{
if (!Page.IsPostBack || !this.EnableViewState)
base.CreateChildControls();
else
_StateHolder.SetItemsForPostBack();
}
}
}
本文轉自
http://www.cnblogs.com/meil/archive/2006/10/19/533838.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.