zoukankan      html  css  js  c++  java
  • ASP.NET AJAX(14)__UpdatePanel与服务器端脚本控件

    脚本控件的作用

    ASP.NET AJAX的脚本控件,连接了服务器端和客户端,因为我们(可以)只在服务器端编程,而效果产生在客户端,这就需要我们首先在服务器端编写一个控件类,然后包含一个或几个脚本文件,其中定义了客户端组件,可以让开发人员只在服务端操作控件,而在页面上添加客户端行为

    一个典型的脚本控件就是UpdateProgress,我们来看一下它的实现方式

    一个UpdateProgress的简单示例

    创建一个aspx页面

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="UpdateProgress.aspx.cs" Inherits="Demo13_UpdateProgress" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            
            <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                <ContentTemplate>
                    <%= DateTime.Now %><br />
                    <asp:Button ID="Button1" runat="server" Text="Update" onclick="Button1_Click" />
                </ContentTemplate>
            </asp:UpdatePanel>
            
            <asp:UpdateProgress ID="UpdateProgress1" runat="server" DisplayAfter="1000">
                <ProgressTemplate>
                    Loading......
                </ProgressTemplate>
            </asp:UpdateProgress>
        </form>
    </body>
    </html>

    在Button1的点击事件里,让线程等待三秒钟

    protected void Button1_Click(object sender, EventArgs e)
        {
            System.Threading.Thread.Sleep(3000);
        }

    开发页面,我们点击按钮Button1,可以看到,等待一秒钟后,出现“Loading…”字样,因为我们设置了UpdateProfress的DisplayAfter为1000,这里代码1000毫秒,而我们让控件的点击事件触发,引发异步回送后,在服务器端停留了三秒钟,所以三秒后,时间更新,同时“Loading…”字样消失

    我们打开在网页中右键选择打开源文件,可在页面的form结束之前找到如下代码

    Sys.Application.add_init(function() {
        $create(Sys.UI._UpdateProgress, {"associatedUpdatePanelId":null,"displayAfter":1000,"dynamicLayout":true}, null, null, $get("UpdateProgress1"));
    });
    

    这段代码,是不是很熟悉呢?没错,如果看过我上一节的文章的,就会很熟悉这种代码格式,它响应了Application的init事件,然后创建一个Sys.UI._UpdateProgress类型的组件,然后设置它绑定的ID,这里是Null,和displayAfter,停留多少毫秒后显示,和UpdateProgress的占位方式,最后,设置的是它要修饰的element

    脚本控件的指责

    • 在页面上引入客户端组件所需要的脚本文件
    • 在页面上生成使用客户端组件的脚本代码

    于是出现了IScriptControl接口

    • IEnumerable<ScriptReference> GetScriptReferences()方法:描述页面中需要加载在页面中的脚本文件
    • IEnumerable<ScriptDescriptor> GetScriptDescriptors()方法:告诉页面需要输出的脚本内容

    如果我们要开发一个脚本控件,除了实现以上的两个方法以外,还需要重写Control类的两个方法

    • OnPreRender
    • OnRender

    由于大部分的脚本控件对于以上两个方法实现相同,因此在开发时候,也可以直接继承ScriptControl类,它已经实现了IScriptControl接口

    一个脚本控件的示例:StyledTextBox

    创建一个名为StyledTextBox.js的文件

    /// <reference name="MicrosoftAjax.js"/>
    
    Type.registerNamespace('Demo');//注册命名控件
    
    Demo.StyledTextBox = function(element) {
        Demo.StyledTextBox.initializeBase(this, [element]);//调用父类构造函数
    
        this._highlightCssClass = null;
        this._nohighlightCssClass = null;
    
        this._onfocusHandler = null;
        this._onblurHandler = null;
    }
    Demo.StyledTextBox.prototype =
    {
        //highlightCssClass属性
        get_highlightCssClass: function() {
            return this._highlightCssClass;
        },
        set_highlightCssClass: function(value) {
            if (this._highlightCssClass !== value) {
                this._highlightCssClass = value;
                this.raisePropertyChanged('highlightCssClass');
            }
        },
    
    
        //nohighlightCssClass属性
        get_nohighlightCssClass: function() {
            return this._nohighlightCssClass;
        },
        set_nohighlightCssClass: function(value) {
            if (this._nohighlightCssClass !== value) {
                this._nohighlightCssClass = value;
                this.raisePropertyChanged('nohighlightCssClass');
            }
        },
    
        initialize: function() {
            Demo.StyledTextBox.callBaseMethod(this, 'initialize');
            
            //创建两个EventHandler
            this._onfocusHandler = Function.createDelegate(this, this._onFocus);
            this._onblurHandler = Function.createDelegate(this, this._onBlur);
            
            //把这两个EventHandler加到我们要修饰的控件上
            $addHandlers(this.get_element(),
                { 'focus': this._onFocus, 'blur': this._onBlur },
                this);
    
            this.get_element().className = this._nohighlightCssClass;
        },
    
        dispose: function() {
            $clearHandlers(this.get_element());
    
            Demo.StyledTextBox.callBaseMethod(this, 'dispose');
        },
    
        //如果获得焦点,把highlightCssClass给到这个element的class上
        _onFocus: function(e) {
            if (this.get_element() && !this.get_element().disabled) {
                this.get_element().className = this._highlightCssClass;
            }
        },
        
        //如果失去焦点,把nohighlightCssClass给到这个element的class上
        _onBlur: function(e) {
            if (this.get_element() && !this.get_element().disabled) {
                this.get_element().className = this._nohighlightCssClass;
            }
        }
    }
    
    Demo.StyledTextBox.registerClass('Demo.StyledTextBox', Sys.UI.Control);
    

    然后创建一个aspx页面

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ScriptControl.aspx.cs" Inherits="Demo13_ScriptControl" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <style type="text/css">
            .NoHighLight
            {
                border:solid 1px gray;
                 background-color:#EEEEEE;
            }
            .HighLight
            {
                border:solid 1px gray;
                background-color:Ivory;
            }
        </style>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Scripts>
                    <asp:ScriptReference Path="~/Demo13/StyledTextBox.js" />
                </Scripts>
            </asp:ScriptManager>
            
            <input type="text" id="textBox" />
            
            <script language="javascript" type="text/javascript">
                Sys.Application.add_init(function() {
                    $create(
                        Demo.StyledTextBox,
                        {
                            highlightCssClass: "HighLight",
                            nohighlightCssClass: "NoHighLight"
                        },
                        null,
                        null,
                        $get("textBox"));
                });
            </script>
        </form>
    </body>
    </html>
    

    代码很简单,和上一讲的如出一辙。。。什么如出一辙,本来就是一回事,文本框获得焦点,样式设置为HighLight,失去焦点,样式设置为NoHighLight。

    这里,我们还是在客户端进行编程的,还没有做到在服务端编写在客户端生效的这样一个效果

    我们开始做一个服务端控件

    创建一个名为StyledTextBox.cs的类

    using System;
    using System.Data;
    using System.Configuration;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;
    using System.Collections.Generic;
    
    namespace Demo
    {
        /// <summary>
        ///StyledTextBox 的摘要说明
        /// </summary>
        //继承自TextBox,实现接口IScriptControl
        public class StyledTextBox : TextBox, IScriptControl
        {
            //两个属性,分别是控件或者焦点和失去焦点时候要设置的样式
            public string HighlightCssClass { get; set; }
            public string NoHighlightCssClass { get; set; }
    
    
            #region IScriptControl 成员
    
            //告诉ScriptManager将如何生成脚本代码
            public IEnumerable<ScriptDescriptor> GetScriptDescriptors()
            {
                ScriptControlDescriptor descriptor = new ScriptControlDescriptor("Demo.StyledTextBox", this.ClientID);//参数1:创建的组件类型,参数2:返回此控件在客户端生成的ID
                //添加两个属性
                descriptor.AddProperty("highlightCssClass", this.HighlightCssClass);
                descriptor.AddProperty("nohighlightCssClass", this.NoHighlightCssClass);
    
                yield return descriptor;
            }
    
            //告诉页面我们要引入的脚本文件
            public IEnumerable<ScriptReference> GetScriptReferences()
            {
                ScriptReference reference = new ScriptReference();
                reference.Path = this.ResolveClientUrl("~/Demo13/StyledTextBox.js");//ResolveClientUrl方法用于浏览器的指定资源的完全限定 URL
    
                yield return reference;
            }
    
            #endregion
    
            //以下是开发一个脚本控件,需要重写Control的两个方法
    
            protected override void OnPreRender(EventArgs e)
            {
                //如果不在设计期间
                if (!this.DesignMode)
                {
                    //把自身注册给ScriptManager的ScriptControl
                    ScriptManager.GetCurrent(this.Page).RegisterScriptControl<StyledTextBox>(this);
                }
    
                base.OnPreRender(e);
            }
    
            protected override void Render(HtmlTextWriter writer)
            {
                if (!this.DesignMode)
                {
                    //把自身注册给ScriptManager的ScriptDescriptors
                    ScriptManager.GetCurrent(this.Page).RegisterScriptDescriptors(this);
                }
                base.Render(writer);
            }
        }
    }
    

    然后修改刚才的aspx页面

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ScriptControl.aspx.cs" Inherits="Demo13_ScriptControl" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <%@ Register Namespace="Demo" TagPrefix="demo" %>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <style type="text/css">
            .NoHighLight
            {
                border:solid 1px gray;
                 background-color:#EEEEEE;
            }
            .HighLight
            {
                border:solid 1px gray;
                background-color:Ivory;
            }
        </style>
    </head>
    <body>
        <form id="form1" runat="server">       
            <input type="text" id="textBox" />
            <asp:ScriptManager runat="server" ID="s"></asp:ScriptManager>       
            <demo:StyledTextBox ID="StyledTextBox1" runat="server" HighlightCssClass="HighLight" NoHighlightCssClass="NoHighLight" />       
        </form>
    </body>
    </html>
    

    注意,这里我们不需要javascript代码,也不需要在页面中引入我们刚才的js文件,只需要在页面中注册这个脚本控件,然后在页面中当作服务端控件那样直接使用,设置属性就可以啦

    我们看到StyledTextBox继承了TextBox,同时扩展了TextBox,这个概念和客户端组件的Control模型很相似,事实上普通的脚本控件包含的脚本中大多数都是定义了客户端的Control模型的组件

    Extender模型

    和客户端的Behavior模型概念类似的服务端模型是Extender模型,可以为一个服务器端控件附加多个Extender,Extender模型理论上继承自IExtenderControl即可,实际上开发时候议案继承自ExtenderControl类,免去一些额外的工作

    开发ExtenderControl需要覆盖一下两个方法

    • IEnumerable<ScriptReference> GetScriptReferences()方法:描述页面中需要加载在页面中的脚本文件
    • IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)方法:需要在目标控件的执行的脚本代码
    一个扩展控件的示例:FocusExtender

    新建一个类库项目,添加引用System.Web和System.Web.Extensions

    创建一个名为FocusBehavior.js的文件

    Type.registerNamespace('Demo');
    
    Demo.FocusBehavior = function(element) {
        Demo.FocusBehavior.initializeBase(this, [element]);
    
        this._highlightCssClass = null;
        this._nohighlightCssClass = null;
    }
    Demo.FocusBehavior.prototype =
    {
        get_highlightCssClass: function() {
            return this._highlightCssClass;
        },
    
        set_highlightCssClass: function(value) {
            if (this._highlightCssClass !== value) {
                this._highlightCssClass = value;
                this.raisePropertyChanged('highlightCssClass');
            }
        },
    
        get_nohighlightCssClass: function() {
            return this._nohighlightCssClass;
        },
    
        set_nohighlightCssClass: function(value) {
            if (this._nohighlightCssClass !== value) {
                this._nohighlightCssClass = value;
                this.raisePropertyChanged('nohighlightCssClass');
            }
        },
    
        initialize: function() {
            Demo.FocusBehavior.callBaseMethod(this, 'initialize');
    
            $addHandlers(this.get_element(),
                { 'focus': this._onFocus, 'blur': this._onBlur },
                this);
    
            this.get_element().className = this._nohighlightCssClass;
        },
    
        dispose: function() {
            $clearHandlers(this.get_element());
    
            Demo.FocusBehavior.callBaseMethod(this, 'dispose');
        },
    
        _onFocus: function(e) {
            if (this.get_element() && !this.get_element().disabled) {
                this.get_element().className = this._highlightCssClass;
            }
        },
    
        _onBlur: function(e) {
            if (this.get_element() && !this.get_element().disabled) {
                this.get_element().className = this._nohighlightCssClass;
            }
        }
    }
    Demo.FocusBehavior.registerClass('Demo.FocusBehavior', Sys.UI.Behavior);
    

    代码和之前的一样,我就没添加注释,看过我之前的文章,看这段代码不是问题

    然后创建一个名为FocusExtender.cs的类文件

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.UI;
    //描述我们需要引用的资源
    [assembly: WebResource("FocusExtender.FocusBehavior.js", "application/x-javascript")]
    namespace FocusExtender
    {
        [TargetControlType(typeof(Control))]
        public class FocusExtender : ExtenderControl
        {
            public string HighlightCssClass { get; set; }
            public string NoHighlightCssClass { get; set; }
    
    
            protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
            {
                ScriptBehaviorDescriptor descriptor = new ScriptBehaviorDescriptor("Demo.FocusBehavior", targetControl.ClientID);
                descriptor.AddProperty("highlightCssClass", this.HighlightCssClass);
                descriptor.AddProperty("nohighlightCssClass", this.NoHighlightCssClass);
    
                yield return descriptor;
            }
    
            protected override IEnumerable<ScriptReference> GetScriptReferences()
            {
                ScriptReference reference = new ScriptReference();
                reference.Assembly = "FocusExtender";
                reference.Name = "FocusExtender.FocusBehavior.js";
    
                yield return reference;
            }
        }
    }
    

    在这里描述应用资源的时候应该注意,这里不是文件名,也不是这个类库的名称加点然后加文件名

    我们点击项目右键属性,打开属性页面

    TM截图未命名

    我们的资源名称,是默认命名控件.文件名称

    这里的代码,与前面的示例唯一不同的是,多了一个targetControl,在类名前加一个标识,表示我们这个控件作用到那种类型的控件上,我们这里设置为“Control”,表示所有控件

    还应该注意一点,我们应该在项目生成操作的时候,把js文件作为嵌入的资源,点击js文件属性,然后在属性对话框里做相应修改

    1

    然后我们就可以在我们的网站里使用它啦

    在网站中点击右键添加引用,选择我们创建的FocusExtender项目,会在bin目录下出现一个FocusExtender.dll,注意要先生成一下

    创建aspx页面

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="FocusExtender.aspx.cs" Inherits="Demo13_FocusExtender" %>
    <%@ Register Assembly="FocusExtender" Namespace="FocusExtender" TagPrefix="demo" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <style type="text/css">
            .NoHighLight
            {
                border:solid 1px gray;
                 background-color:#EEEEEE;
            }
            .HighLight
            {
                border:solid 1px gray;
                background-color:Ivory;
            }
        </style>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            
            <asp:TextBox runat="server" ID="textBox" />
            
            <demo:FocusExtender ID="FocusExtender1" runat="server" TargetControlID="textBox" HighlightCssClass="HighLight" NoHighlightCssClass="NoHighLight" />
            
            <asp:Panel Width="200" Height="200" ID="panel" runat="server">Hello World!</asp:Panel>
            
            <demo:FocusExtender ID="FocusExtender2" runat="server" TargetControlID="panel" HighlightCssClass="HighLight" NoHighlightCssClass="NoHighLight" />
        </form>
    </body>
    </html>
    

    这样,我们把我们创建的控件“附加”到了一个文本框和一个Panel上,在同时我们提供了三个属性,作用的控件,和两个样式属性,运行页面,得到与前面我们的脚本控件相同的效果

    脚本控件和Extender模型

    • IScriptControl:对应Sys.Component__ScriptComponentDescriptor
    • ScriptComtrol:对应Sys.UI.Control__ScriptControlDescript
    • ExtenderControl:对应Sys.UI.Behavior__ScriptBehaviroDescriptor

    在PostBack中保持状态

    • 与普通服务器控件不同,ScriptControl的精髓在客户端,在普通的服务端控件中使用ViewSate并,它不能保持客户端状态
    • 组件状态可能在客户端被改变
    • 需要在PostBack前后保持客户端状态

    在异步刷新中,由于不刷新整个页面,因此可以保存在页面变量中,但是完整的PostBack需要将状态从客户端提交到服务器端,然后再写回给客户端,客户端向服务器端提交信息的方法有以下三种

    • Query String(改变URL)
    • Cookie(作用域太大)
    • Input+Post

    那么,如果我们要保存页面的某个状态,就分两种情况啦

    一种是异步刷新,因为异步刷新的时候,页面并没有销毁,所以,我们可以把保存这种状态的键值放在window对象或者一个HiddenField中,但是如果是传统的更新,页面是会被销毁的,则只能保存在HiddenField中啦

    在UpdatePanel中使用内联脚本

    • UpdatePanel在更新时使用的是设置innerHTML的做法
    • 设置innerHTML并不会执行其中的内联脚本
    • 需要把内联脚本提出来,然后eval

    为了让UpdatePanle可以使用内联脚本,就需要使用一个内联脚本控件

    内联脚本

    • 要子啊异步更新后执行脚本,唯一的方法就是调用ScriptManager的脚本注册方法
    • 开发一个控件,在普通加载时简单输出内联脚本,在异步更新时调用脚本注册方法
    一个内联脚本的示例

    创建一个aspx页面

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="InlineScripts.aspx.cs" Inherits="Demo13_InlineScripts" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server" ID="sm" />
            
            <asp:UpdatePanel runat="server" ID="update">
                <ContentTemplate>                
                    <%= DateTime.Now %>
                    <asp:Button runat="server" ID="btnRefresh" Text="Refresh" />
                    
                        <script language="javascript" type="text/javascript">
                            alert("Xiaoyaojian");
                        </script>
                </ContentTemplate>
            </asp:UpdatePanel>
        </form>
    </body>
    </html>
    

    打开页面,刷新页面,都会弹出提示框,而在我们点击Refresh后,脚本却并没有被执行,这不是我们想要的效果,但是这里的脚本在异步回送的时候确实是被加载啦,那要怎么做呢  。。。。。

    我们创建一个名为InlineScript的类库项目,添加一个类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Web.UI;
    using System.IO;
    
    namespace InlineScript
    {
        public class InlineScript : Control
        {
            //重写Render方法,每次UpdatePanle更新,这个方法都会被调用
            protected override void Render(HtmlTextWriter writer)
            {
                ScriptManager sm = ScriptManager.GetCurrent(this.Page);
    
                if (sm.IsInAsyncPostBack)//如果页面是异步更新的情况下
                {
                    StringBuilder sb = new StringBuilder();
                    base.Render(new HtmlTextWriter(new StringWriter(sb)));
                    //得到的UpdatePanel中的script标签的所有内容
                    string script = sb.ToString();
                    ScriptManager.RegisterStartupScript(this, typeof(InlineScript), this.UniqueID, script, false);//把这段脚本注册到页面上
                }
                else
                {
                    base.Render(writer);
                }
            }
        }
    }
    

    生成项目,然后和上面一样,在网站项目中添加对这个项目的引用,然后修改上面的页面

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="InlineScripts.aspx.cs" Inherits="Demo13_InlineScripts" %>
    <%@ Register Assembly="InlineScript" Namespace="InlineScript" TagPrefix="demo" %><%--注册这个控件--%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server" ID="sm" />
            
            <asp:UpdatePanel runat="server" ID="update">
                <ContentTemplate>
                    <%= DateTime.Now %>
                    <asp:Button runat="server" ID="btnRefresh" Text="Refresh" />
                    <%--使用注册的控件--%>
                    <demo:InlineScript runat="server">
    
                        <script language="javascript" type="text/javascript">
                            alert("Xiaoyaojian");
                        </script>
    
                    </demo:InlineScript>
                </ContentTemplate>
            </asp:UpdatePanel>
        </form>
    </body>
    </html>
    

    打开页面,刷新,点击按钮,都会弹出提示框,对嘛   这才是我们要的效果

  • 相关阅读:
    matlab练习程序(RGB2HSV、HSV2RGB)
    matlab练习程序(距离变换)
    C++生成xml(使用tinyxml)
    matlab练习程序(RGB2YUV、YUV2RGB)
    修改 Google Desktop 的缓存目录
    Access 2003 中 null 和 '' 空字符串的奇怪问题
    娃娃
    【js:片断】jQuery 设置 select 下拉框的选中状态
    由 TypeInitializationException 引起的问题
    afaca 分析报告
  • 原文地址:https://www.cnblogs.com/xiaoyaojian/p/2224182.html
Copyright © 2011-2022 走看看