惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Security @ Cisco Blogs
雷峰网
雷峰网
T
Threat Research - Cisco Blogs
D
Docker
The Hacker News
The Hacker News
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Project Zero
Project Zero
C
Cyber Attacks, Cyber Crime and Cyber Security
Simon Willison's Weblog
Simon Willison's Weblog
The GitHub Blog
The GitHub Blog
Spread Privacy
Spread Privacy
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
AWS News Blog
AWS News Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
U
Unit 42
Martin Fowler
Martin Fowler
T
Threatpost
S
Schneier on Security
Know Your Adversary
Know Your Adversary
V
Vulnerabilities – Threatpost
AI
AI
T
Tenable Blog
K
Kaspersky official blog
博客园 - 叶小钗
V
V2EX
C
CERT Recently Published Vulnerability Notes
博客园 - 聂微东
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
A
Arctic Wolf
H
Heimdal Security Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Google DeepMind News
Google DeepMind News
T
Tor Project blog
J
Java Code Geeks
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Vercel News
Vercel News
B
Blog
P
Proofpoint News Feed
爱范儿
爱范儿
WordPress大学
WordPress大学
I
InfoQ
小众软件
小众软件
月光博客
月光博客
MyScale Blog
MyScale Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Jina AI
Jina AI
Help Net Security
Help Net Security

博客园 - williambirkin

.NET平台自带的AOP机制 转自《设计模式--基于c#的工程化实现及扩展》 今天看PolicyInjection遇到的问题 转 事务隔离级别 转 UML 基础: 类图 关于Form.show的问题 关于where中子查询的性能问题 请高手指教 模式 转 SQL Server 索引结构及其使用 (三) 转 SQL Server 索引结构及其使用 (二) 转 SQL Server 索引结构及其使用 (一) 泛型的一点思考 摘自《.NET 2.0 模式开发实战》 转 《为Windows应用创建简单的异步调用模式》 转 C#格式化数值结果表(格式化字符串) SQL游标的简单使用 转“理解VC# 2005中的字符串和正规表达式” 2个IP输入控件 Windows Forms中禁用窗体的关闭按钮 回车移动焦点 文本框事件顺序
我的第一个ASP.NET Ajax控件
williambirkin · 2009-12-26 · via 博客园 - williambirkin

这是我自己写的第一个基于Microsoft AJAX Library的Ajax控件。

这个是一个类似google输入框的AJAX控件。应该是很常见的,网上也有不少用别的AJAX类库实现的例子。
JS组件的代码是从《ASP.Net3.5控件和组件开发技术》提供的一个ajaxpro实现的示例的版本上改进过来的。
毕竟这也不是什么新功能了,能复用就复用吧:)。

solution

AutoFilterTextBoxACT.cs是控件的服务端组件代码,autoFilterTextBoxACT.js是客户端组件代码。
setTimeoutExtend.js是为了扩展setTimeout的js代码。
WSUrlEditor.cs是组件的属性用到的一个设计器。

1.服务器端代码
服务器端的基本代码比较简单,与普通的asp.net控件开发相比这里的变化主要是派生控件继承了新的控件类型ScriptControl。

ScriptControl 主要是用来在派生的控件的PreRender 阶段检查Page上是否包含ScriptManager控件。在Render时期使用ScriptManager为派生类注册脚本。
ScriptControl继承了WebControl和IScriptControl。IScriptControl接口使派生控件提供启用Ajax功能所必须的JavaScript资源。
IScriptControl.GetScriptDescriptors方法返回ScriptDescriptor对象集合。ScriptDescriptor用来提供创建客户端类的一个实例的脚本。
IScriptControl.GetScriptReferences方法返回用于定义控件需要的脚本资源的 ScriptReference 对象的集合。

实现代码如下:

        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            //因为只有一个需要实例化的客户端组件,所以只需要添加一个ScriptControlDescriptor实例。
            ScriptControlDescriptor descriptor = new ScriptControlDescriptor("AutoFilterTextBox.AutoFilterTextBoxACT", this.ClientID);

            //添加实例客户端组件时需要初始化的实例的属性。
            descriptor.AddProperty("clientID", this.ClientID);
            descriptor.AddProperty("queryFieldName", this.ClientID + "_" + this.txt.ClientID);
            descriptor.AddProperty("dataSourceURI", this.Page.ResolveUrl(this.DataSourceURI));
            descriptor.AddProperty("getDataSucceededHandle", this.GetDataSucceededHandle);
            descriptor.AddProperty("preGetDataHandle", this.PreGetDataHandle);
            descriptor.AddProperty("serviceMethodName", this.ServiceMethodName);

            return new ScriptDescriptor[] { descriptor };    
        }

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            //使用ScriptManager获得资源中的js文件
            string autoFilterTextBoxACT =
                Page.ClientScript.GetWebResourceUrl(this.GetType(), "AutoFilterTextBox.autoFilterTextBoxACT.js");
            string setTimeoutExtend =
                Page.ClientScript.GetWebResourceUrl(this.GetType(), "AutoFilterTextBox.setTimeoutExtend.js");

            //提供所有用到的资源文件的引用。这些引最终用会被添加到Page.ClientScript中,并被输出到客户端。
            return new ScriptReference[] { new ScriptReference(autoFilterTextBoxACT), new ScriptReference(setTimeoutExtend) };
        }
ScriptDescriptor生成的初始化js组件的代码:
<script type="text/javascript"> //<![CDATA[ Sys.Application.initialize(); 
Sys.Application.add_init(function() { 
$create(AutoFilterTextBox.AutoFilterTextBoxACT, {"clientID":"AutoFilterTextBoxACT1","dataSourceURI":"/TestWebSite/Services/BookNameListService.asmx","getDataSucceededHandle":"OnClientGetDataSucceeded","preGetDataHandle":"OnPreGetDataHandle","queryFieldName":"AutoFilterTextBoxACT1_tb","serviceMethodName":"GetBookNameArray"}, null, null, 
$get("AutoFilterTextBoxACT1")); }); //]]> </script>

其他的部分请看源码。

2.客户端代码
与普通的js组件编程相比也没什么特别的。主要是下面五个步骤:
第一步:注册命名空间;

/// <summary>
/// 注册命名空间:AutoFilterTextBox
/// </summary>
Type.registerNamespace("AutoFilterTextBox");


第二部:定义类、构造函数和初始化代码;

/// <summary>
/// 客户端对象AutoFilterTextBox类实现
/// </summary>
//构造方法
AutoFilterTextBox.AutoFilterTextBoxACT = function(element) {
    AutoFilterTextBox.AutoFilterTextBoxACT.initializeBase(this, [element]); //初始化基类    

    this.DIV_BG_COLOR = "#c0c1f9";
    this.DIV_HIGHLIGHT_COLOR = "#7d84ef"
    this.DIV_FONT = "Arial";
    this.DIV_PADDING = "2px";
    this.DIV_BORDER = "1px solid #020086";
    this._clientID;
    this._queryField;
    this._queryFieldName;
    this._divName;
    this._ifName;
    this._lastVal = "";
    this._val = "";
    this._globalDiv;
    this._divFormatted = false;
    this._dataSourceURI = "";
    this._getDataSucceededHandle;
    this._preGetDataHandle;
    this._serviceMethodName = "";
}


第三步:编写类的属性和方法;

AutoFilterTextBox.AutoFilterTextBoxACT.prototype =
{
    ///方法
    initialize: function() {
        AutoFilterTextBox.AutoFilterTextBoxACT.callBaseMethod(this, "initialize");
        this.doInitialize();
        //注册初始化事件
    },
    doInitialize: function() {
        this._queryField = document.getElementById(this._queryFieldName);
        this._queryField.autocomplete = "off";

        if (this.hiddenDivName) {
            this._divName = this.hiddenDivName;
        }
        else {
            this._divName = this._clientID + "_querydiv";
        }

        this._ifName = this._clientID + "_queryiframe";

        this._lastVal = this._val = escape(this._queryField.value);
        //注册初始化事件
        $addHandler(this._queryField, "blur", Function.createDelegate(this, this.hideDiv));
        $addHandler(this._queryField, "keydown", Function.createDelegate(this, this.keypressHandler));

        setTimeout(this.mainLoop, 100, this, null);
    },
    Dispose: function() {
        AutoFilterTextBox.AutoFilterTextBoxACT.callBaseMethod(this, 'dispose');
    },
    get_queryFieldName: function() {
        return this._queryFieldName;
    },
    set_queryFieldName: function(value) {
        this._queryFieldName = value;
    },
    get_clientID: function() {
        return this._clientID;
    },
    set_clientID: function(value) {
        this._clientID = value;
    },
    get_dataSourceURI: function() {
        return this._dataSourceURI;
    },
    set_dataSourceURI: function(value) {
        this._dataSourceURI = value;
    },
    get_getDataSucceeded: function() {
        return this._getDataSucceeded;
    },
    set_getDataSucceeded: function(value) {
        this._getDataSucceeded = value;
    },
    …省略
}


第四步:注册类;

/// <summary>
/// 注册类, 并继承Sys.UI.Control
/// </summary>
AutoFilterTextBox.AutoFilterTextBoxACT.registerClass('AutoFilterTextBox.AutoFilterTextBoxACT', Sys.UI.Control);


第五步:通知脚本加载完成。

/// <summary>
/// 通知脚本加载完成
/// 说明: 若要向 ScriptManager 控件注册的所有独立脚本文件必须调用 notifyScriptLoaded 方法以通知应用程序,脚本已完成加载。
/// 嵌入到程序集中的脚本在大多数情况下不应调用此方法。有关更多信息,请参见 Sys.Application.notifyScriptLoaded 方法。
/// </summary>
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
 

有几个地方需要注意:

(1)创建DOM对象的事件首先要使用Function.createDelegate方法,创建一个event delegate。需要注意一下Function.createDelegate的两个参数。第一个参数instance,表示事件中this引用的对象。第二个参数表示事件的handle。如果传入的instance是某个dom元素那么事件中的this将是该dom元素。为了方便的访问组件中的属性和方法,我将组件实例(this)作为instance参数。


(2)在创建完代理类之后使用$addHandler方法注册dom元素的事件。注册事件的时候,事件的名称不要带“on”。因为$addHandler方法会自动帮你加上。
例如
$addHandler(this._queryField, "onkeydown", Function.createDelegate(this, this.keypressHandler));
实际上注册的是ononkeydown事件。


(3)需要暴露给服务器端代码初始化的js组件的属性必须使用get_和set_进行封装。

3.组件的使用

aspx

几个关键属性

  1. ServiceMethodName表示要调用的WebService的方法
  2. DataSourceURI表示WebService的地址
  3. PreGetDataHandle表示调用WebService前为组件提供WebService所需参数的方法
  4. GetDataSucceededHandle表示成功调用WebService后客户端对返回数据处理的方法

这几个属性基本上都是为了使控件的使用更加灵活方便,使控件的使用者能参与Ajax过程中的相关处理,提供一定的扩展性。
到此为止此控件中与ASP.NET Ajax相关的部分都已经说了。至于其他部分的代码基本属于普通的js和服务器控件编程,这里就不一一详说了。
对于ASP.NET Ajax服务器控件的开发我也是新手,欢迎大家批评。

源码: