增强DropDownList和ListBox控件:保持客户端脚本添加的options

来源:互联网 发布:网吧拦截关机软件 编辑:程序博客网 时间:2024/06/05 04:02
导读:
   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  
原创粉丝点击