zoukankan      html  css  js  c++  java
  • 服务器自定义开发二之客户端脚本回发


        上一篇文章介绍了一个复合控件,下面将介绍ListPicker自定义控件,ListPicker是一个较复杂的自定义控件。因为它需要和脚本代码进行交互。

    ASP.NET 服务器控件可以发送两种客户端脚本:客户端脚本块 和客户端 HTML 属性
      客户端脚本块通常是用 JavaScript 编写的,其中通常包含在发生特定的客户端事件时执行的函数。客户端 HTML 属性提供将客户端事件与客户端脚本联系在一起的方法。例如,以下的 HTML 页面中包含了客户端脚本块,脚本块中包含了名为 doClick() 的函数。该页面同时还包含一个按钮(通过 <input> HTML 元素创建),这个按钮的 onclick 属性与 doClick() 函数绑定。也就是说,只要用户单击该按钮,就开始执行 doClick() 函数中的客户端代码。在本示例中,将显示一个弹出式对话框。 如下:
    <html>
    <body>
    <form>
    <script language="JavaScript">
    <!--function doClick() {alert("You clicked me!");} -->
    </script>

    <input type="button" onclick="doClick()" value="Click Me!" />
    </form>
    </body>
    </html>


       对于以上 HTML 页面中的客户端脚本,客户端脚本块包含在 HTML 注释(<!-- 和 -->)中。之所以这样,是因为如果不将脚本块放入 HTML 注释中,那些不能识别脚本的旧式浏览器就会显示 <script> 块的内容。
       在上面的 HTML 页面中,<input> 元素的 onclick 属性绑定到 doClick() 函数,因此在单击该按钮时将执行 doClick() 函数。
    在使用客户端脚本时,只有两个 HTML 窗体元素(“按钮”(Button) 和“图像按钮”(ImageButton))引起窗体回发。如果自定义控件呈现不引起回发的 HTML 元素(如“文本框”(TextBox) 或“链接按钮”(LinkButton)),而您希望控件启动回发,则可以在 ASP.NET 中通过依靠客户端脚本(JScript、JavaScript)的事件结构进行编程来实现这一功能。
    要启用这种回发机制, 启动回发必须在控件 Render 方法中添加的代码,示意如下。
    protected override void Render(HtmlTextWriter output) {
                      output.Write("<a  id=\"" + this.UniqueID + "\" href=\"javascript:" + Page.GetPostBackEventReference(this) +"\">");
                      output.Write(" " + this.UniqueID + "</a>");
                }

       代码里GetPostBackEventReference 方法发出启动回发的客户端脚本,并且还提供对启动回发事件的控件的引用。如果控件要捕获回发事件(来自客户端的窗体提交),它必须实现 System.Web.UI.IPostBackEventHandler 接口。此接口向 ASP.NET 页框架发出信号,指出控件希望收到回发事件通知。RaisePostBackEvent 方法允许控件处理该事件和引发其他事件。
     通常我们可以使用GetPostBackEventReference传递参数,请看下面示意代码:

       

    using System;
    using System.Web;
    using System.Web.UI;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Web.UI.WebControls;

    namespace Ctrl {

        public class Ctrl : Control, IPostBackDataHandler, IPostBackEventHandler {

            private int _value = 0;

            public int Value { get { return _value; }        set {  _value = value;   }   }

            public bool LoadPostData(String postDataKey, NameValueCollection values) {
               _value = Int32.Parse(values[this.UniqueID]);
               return false;
            }

            public void RaisePostDataChangedEvent() {    }


            public void RaisePostBackEvent(String eventArgument) {
              
               if (eventArgument == "加") {   this.Value++;      }
               else {    this.Value--;      }
            }

            protected override void OnPreRender(EventArgs e) {     }

            protected override void Render(HtmlTextWriter output) {
               output.Write("<h3>值:<input name=" + this.UniqueID + " type=text value=" + this.Value + "> </h3>");
               output.Write("<input type=button value=加
    OnClick=\"jscript:"+ Page.GetPostBackEventReference(this, "加")+ "\"> |");
               output.Write("<input type=button value=减
    OnClick=\"jscript:"+ Page.GetPostBackEventReference(this, "减")+ "\">");
            }   
        }   
    }

     当时用GetPostBackEventReference输出脚本时,它的两个参数分别是:this和加(减),其中this用于表示回发控件本省,当我们使用如下方式使用该自定义控件时
    <%@ Register TagPrefix="Ctrl" Namespace="Ctrl" Assembly="Ctrl" %>

    <html>
       <body>
          <form method="POST" action="NonComposition2.aspx" runat=server>
              <Ctrl:Ctrl id="MyControl" runat=server/>
          </form>
       </body>
    </html>


    如果浏览服务器发给客户端的代码,就如下:

    <html>

       <body>

          <form name="_ctl0" method="POST" action="Ctrl.aspx" id="_ctl0">
    <input type="hidden" name="__VIEWSTATE" value="dDwtMTAwOTQyOTI0Nzs7PomXs73t9xBOKEFKyYyTmD+75ZXL" />


              <h3>值:<input name=MyControl type=text value=0> </h3><input type=button value=加 OnClick="jscript:__doPostBack('MyControl','加')"> |<input type=button value=减 OnClick="jscript:__doPostBack('MyControl','减')">

         
    <input type="hidden" name="__EVENTTARGET" value="" />
    <input type="hidden" name="__EVENTARGUMENT" value="" />

    <script language="javascript" type="text/javascript">
    <!--
     function __doPostBack(eventTarget, eventArgument) {
      var theform;
      if (window.navigator.appName.toLowerCase().indexOf("microsoft") > -1) {
       theform = document._ctl0;
      }
      else {
       theform = document.forms["_ctl0"];
      }
      theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
      theform.__EVENTARGUMENT.value = eventArgument;
      theform.submit();
     }
    // -->
    </script>
    </form>

       </body>

    </html>


    本例中用粗体显示的元素(两个隐藏字段和客户端脚本方法)是由 ASP.NET 页框架添加的。隐藏窗体字段指示要发送到哪个服务器控件,并可以指定一个要传递的参数。客户端脚本方法用于设置隐藏字段,并将窗体提交给服务器.
    所以,我们可以在Ctrl自定义控件里使用
      public void RaisePostBackEvent(String eventArgument) {
              
               if (eventArgument == "加") {   this.Value++;      }
               else {    this.Value--;      }
            }
    的代码获取参数并进行判断。
     在ListPicker.cs源代码里还调用Page的RegisterHiddenField额外注册了两个隐藏元素,如下
       Page.RegisterHiddenField(SelectedHelperID, String.Join(",", SelectedItems ));
       Page.RegisterHiddenField(AllHelperID, String.Join(",", AllItems ));

    那么为什么要注册这两个隐藏控件哪?
    我们先通过一个简单的javascript代码进行说明,下面是一段较为简单的脚本控件,它用于同步用户的选项,如下:

    <SCRIPT  LANGUAGE="javascript"> 

    function  setcity()  { 

    switch  (document.shengshi.shengID.value)  { 
    case  '江苏'  : 
    var  labels  =  new  Array("南京","无锡","苏州"); 
    var  values  =  new  Array("nj","wx","sz"); 
    break; 

    case  '安徽'  : 
    var  labels  =  new  Array("合肥","蚌埠","淮北"); 
    var  values  =  new  Array("hf","bb","hb"); 
    break 

    //  清空市列表选择框的内容 

    document.shengshi.shiID.options.length  =  0; 

    //  从数组中添加内容 

    for(var  i  =  0;  i  <labels.length;  i++)  { 

    document.shengshi.shiID.add(document.createElement("OPTION")); 
    document.shengshi.shiID.options[i].text=labels[i]; 
    document.shengshi.shiID.options[i].value=values[i]; 

    //  选择第一个选项 

    document.shengshi.shiID.selectedIndex  =  0; 

    </SCRIPT> 
    </HEAD> 
    <BODY> 
    <FORM  NAME="shengshi"> 

    省: 
    <SELECT  NAME="shengID"  OnChange="setcity()"> 
    <OPTION  value="江苏">江苏</OPTION> 
    <OPTION  value="安徽"  SELECTED>安徽</OPTION> 
    </SELECT> 

    市: 

    <SELECT  NAME="shiID"></SELECT> 
    </FORM> 
    <!--  执行初始化选择列表  --> 
    <SCRIPT  LANGUAGE="javascript"> 
    setcity(); 
    </SCRIPT> 


    运行这段代码,当你在左边下拉框选择不同的省份,相应的右边下拉框里显示相应省份里的市区,但是现在有一个问题,不管你新选择哪个省份或者市区,你查看它的源代码,它生成的HTML代码保持不变,所以如果将该数据提交到服务器后,你得到的输出结果永远都是空值。
       这是因为javascript是由浏览器内部运行机制实现的,并不体现在HTML代码上,所以为了解决这个问题,我们同样需要使用javascript保存用户的选项,后面读者可以看到ListPicker通过注册隐藏字段实现运行。这个是后面ListPicker实现的核心
     事实上,也是我们常用的DropDownList、ListBox等实现的核心方式。(未完)

  • 相关阅读:
    阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_04-用户认证技术方案-SpringSecurityOauth2
    阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_03-用户认证技术方案-Oauth2协议
    阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_02-用户认证技术方案-单点登录
    阶段5 3.微服务项目【学成在线】_day16 Spring Security Oauth2_01-用户认证需求分析
    阶段5 3.微服务项目【学成在线】_day08 课程图片管理 分布式文件系统_06-分布式文件系统研究-fastDFS安装及配置文件说明
    阶段5 3.微服务项目【学成在线】_day08 课程图片管理 分布式文件系统_05-分布式文件系统研究-fastDSF文件上传和下载流程
    阶段5 3.微服务项目【学成在线】_day08 课程图片管理 分布式文件系统_04-分布式文件系统研究-fastDSF架构介绍
    阶段5 3.微服务项目【学成在线】_day08 课程图片管理 分布式文件系统_02-分布式文件系统研究-什么是文件系统
    阶段5 3.微服务项目【学成在线】_day08 课程图片管理 分布式文件系统_03-分布式文件系统研究-什么是分布式文件系统
    阶段5 3.微服务项目【学成在线】_day08 课程图片管理 分布式文件系统_01-分布式文件系统研究-技术应用场景
  • 原文地址:https://www.cnblogs.com/mqingqing123/p/290281.html
Copyright © 2011-2022 走看看