向 Web 服务器控件添加客户端功能

更新:2007 年 11 月

ASP.NET 中的 AJAX 功能使您能够扩展 Web 应用程序的功能以创建丰富的用户体验。可以使用 Web 浏览器的 ECMAScript (JavaScript)、DHTML 和 AJAX 功能,提供可视化效果、客户端处理(如验证)等。

本主题演示如何创建将 ASP.NET 的 AJAX 功能用于浏览器中的扩展功能的自定义 Web 服务器控件。通过使用客户端控件,可向客户端文档对象模型 (DOM) 元素添加功能。通过在服务器控件中实现 IScriptControl 接口,可将客户端控件与服务器控件关联。

在本主题中您将了解如何执行以下操作:

  • 创建一个 Web 服务器控件,该控件封装客户端行为并包含用户可用来设置控制行为的属性。

  • 创建与 Web 服务器控件关联的客户端控件。

  • 通过客户控件中的浏览器 DOM 处理事件。

    Bb386450.alert_note(zh-cn,VS.90).gif说明:

    也可通过创建扩展程序控件将丰富的客户端功能添加到 Web 服务器控件中。此扩展程序控件将客户端功能封装到一个行为中,然后可将其附加到 Web 服务器控件中。由于扩展程序控件不属于其关联控件的一部分,因此您可以创建单个可与多种类型的 Web 服务器控件关联的扩展程序控件。有关示例,请参见创建扩展程序控件以将客户端行为与 Web 服务器控件关联

  • 将自定义 Web 服务器控件编译到一个程序集中,并将关联的 JavaScript 文件作为资源嵌入到同一程序集中。

  • 在支持 AJAX 的 ASP.NET 网页中引用已编译的自定义 Web 服务器控件。

标识客户端要求

将客户端行为添加到 Web 服务器控件的第一步是确定浏览器中将包含的控件行为,然后确定实现此行为所需的客户端功能。

本主题中创建的 Web 服务器控件可实现简单的客户端行为。当控件(TextBox 控件)在浏览器中被选定(或具有焦点)时,将突出显示该控件。例如,该控件在具有焦点时可能更改背景色,然后在焦点移动到另一个控件时返回到默认颜色。

若要实现此行为,本主题中的客户端控件需要下表中列出的功能。

  • 用于突出显示 DOM 元素的方法。
    为了在 ASP.NET 网页中突出显示 DOM 元素,客户端控件应用一个用类名称标识的级联样式表 (CSS) 样式。此样式可由用户配置。

  • 用于将 DOM 元素返回到其非突出显示状态的方法。
    为了从 ASP.NET 网页中移除对 DOM 元素的突出显示,客户端控件应用一个用类名称标识的 CSS 样式。此样式可由用户配置并作为默认样式应用于 DOM 元素。

  • 用于标识何时选定 DOM 元素的方法。
    为了标识 DOM 元素何时被选定(具有焦点),该控件将处理 DOM 元素的 onfocus 事件。

  • 用于标识何时不选定 DOM 元素的方法。
    为了标识何时不再选定某个控件,该控件将处理 DOM 元素的 onblur 事件。

创建 Web 服务器控件

通过使用 ASP.NET AJAX 功能来包含客户端功能的 Web 服务器控件与任何其他 Web 服务器控件类似。不过,该控件还从 System.Web.UI 命名空间实现 IScriptControl 接口。本主题中的控件通过继承 TextBox 类并实现 IScriptControl 接口来扩展 ASP.NET TextBox 控件。

下面的示例演示类定义。

Public Class SampleTextBox
    Inherits TextBox
    Implements IScriptControl
public class SampleTextBox : TextBox, IScriptControl

新的 Web 服务器控件包括两个用于实现客户端要求的属性:

  • HighlightCssClass,用于标识在 DOM 元素具有焦点时对其应用的 CSS 类以便突出显示该控件。

  • NoHighlightCssClass,用于标识在 DOM 元素没有焦点时对其应用的 CSS 类。

实现 IScriptControl 接口

下表列出了必须在 Web 服务器控件中实现的 IScriptControl 接口的成员。

  • GetScriptDescriptors
    返回 ScriptDescriptor 对象的集合,这些对象包含有关与 Web 服务器控件一起使用的客户端组件的实例的信息。其中包括要创建的客户端类型、要分配的属性和要向其添加处理程序的事件。

  • GetScriptReferences
    返回 ScriptReference 对象的集合,这些对象包含有关与该控件一起提供的客户端脚本库的信息。这些客户端脚本库定义客户端类型和该行为所需的任何其他 JavaScript 代码。

本主题中的 Web 服务器控件使用 GetScriptDescriptors 方法来定义客户端控件类型的实例。该控件创建新的 ScriptControlDescriptor 对象(ScriptControlDescriptor 类派生自 ScriptDescriptor 类)并在 GetScriptDescriptors 方法的返回值中包含此对象。

ScriptControlDescriptor 对象包括客户端类的名称 (Samples.SampleTextBox) 和 Web 服务器控件的 ClientID 值。此值可用作呈现的 DOM 元素的 id 值。将客户端类名称和 ClientID 属性值传递给 ScriptControlDescriptor 对象的构造函数。

ScriptControlDescriptor 类用于设置客户端控件的属性值,这些属性值是从 Web 服务器控件的属性中获得的。为了定义客户端控件的属性,Web 服务器控件使用 ScriptControlDescriptor 类的 ScriptComponentDescriptor.AddProperty 方法。然后,Web 服务器控件根据其相应的属性为客户端控件的属性指定名称和值。此示例使用 ScriptControlDescriptor 对象来设置客户端控件中的 highlightCssClass 和 nohighlightCssClass 属性的值。

Web 服务器控件在 GetScriptDescriptors 方法的返回值中提供 ScriptControlDescriptor 对象。因此,当对浏览器呈现 Web 服务器控件时,ASP.NET 将呈现 JavaScript,此 JavaScript 使用所有定义的属性和事件处理程序创建客户端控件的实例。根据 Web 服务器控件中呈现的 ClientID 属性,将控件实例附加到 DOM 元素。下面的示例演示声明性 ASP.NET 标记,此标记在一个页中包含本主题中的 Web 服务器控件。

<sample:SampleTextBox runat="server"
  ID="SampleTextBox1"
  HighlightCssClass="MyHighLight"
  NoHighlightCssClass="MyLowLight" />

呈现的页输出包括对 $create 方法的调用,此方法标识要创建的客户端类。该页还提供客户端属性的值和与客户端控件关联的 DOM 对象的 id 值。下面的示例演示呈现的 $create 方法。

$create(Samples.SampleTextBox, {"highlightCssClass":"MyHighLight","nohighlightCssClass":"MyLowLight"}, null, null, $get('SampleTextBox1'));

该示例 Web 服务器控件使用 GetScriptReferences 方法来传递定义客户端控件类型的脚本库的位置。在此示例中,这是一个指向名为 SampleTextBox.js 的脚本文件的 URL,此脚本文件将在后面创建。通过创建新的 ScriptReference 对象,然后将 Path 属性设置为包含客户端代码的文件的 URL 来创建引用。

下面的示例演示 GetScriptDescriptorsGetScriptReferences 方法的实现。

Protected Overridable Function GetScriptReferences() As IEnumerable(Of ScriptReference)
    Dim reference As ScriptReference = New ScriptReference()
    reference.Path = ResolveClientUrl("SampleTextBox.js")

    Return New ScriptReference() {reference}
End Function

Protected Overridable Function GetScriptDescriptors() As IEnumerable(Of ScriptDescriptor)
    Dim descriptor As ScriptControlDescriptor = New ScriptControlDescriptor("Samples.SampleTextBox", Me.ClientID)
    descriptor.AddProperty("highlightCssClass", Me.HighlightCssClass)
    descriptor.AddProperty("nohighlightCssClass", Me.NoHighlightCssClass)

    Return New ScriptDescriptor() {descriptor}
End Function

Function IScriptControlGetScriptReferences() As IEnumerable(Of ScriptReference) Implements IScriptControl.GetScriptReferences
    Return GetScriptReferences()
End Function

Function IScriptControlGetScriptDescriptors() As IEnumerable(Of ScriptDescriptor) Implements IScriptControl.GetScriptDescriptors
    Return GetScriptDescriptors()
End Function
protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
    ScriptReference reference = new ScriptReference();
    reference.Path = ResolveClientUrl("SampleTextBox.js");

    return new ScriptReference[] { reference };
}

protected virtual IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor("Samples.SampleTextBox", this.ClientID);
    descriptor.AddProperty("highlightCssClass", this.HighlightCssClass);
    descriptor.AddProperty("nohighlightCssClass", this.NoHighlightCssClass);

    return new ScriptDescriptor[] { descriptor };
}

IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
{
    return GetScriptReferences();
}

IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
{
    return GetScriptDescriptors();
}

注册客户端控件

必须向当前页的 ScriptManager 对象注册客户端控件。这可以通过调用 ScriptManager 类的 RegisterScriptControl<TScriptControl> 方法并提供对客户端控件的引用来实现。

该示例 Web 服务器控件向页上的 ScriptManager 控件将其自身注册为客户端控件。为此,该控件将重写基 TextBox 控件的 OnPreRender 方法。然后,调用 RegisterScriptControl() 方法以将其自身注册为客户端控件。此外,该控件将对由 GetScriptDescriptors 方法创建的脚本说明符进行注册。它通过调用控件的 Render 方法中的 RegisterScriptDescriptors() 方法来执行此操作。

下面的示例演示对 RegisterScriptControl() 和 RegisterScriptDescriptors() 方法的调用。

Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
    If Not Me.DesignMode Then

        ' Test for ScriptManager and register if it exists
        sm = ScriptManager.GetCurrent(Page)

        If sm Is Nothing Then _
            Throw New HttpException("A ScriptManager control must exist on the current page.")

        sm.RegisterScriptControl(Me)
    End If

    MyBase.OnPreRender(e)
End Sub

Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
    If Not Me.DesignMode Then _
      sm.RegisterScriptDescriptors(Me)

    MyBase.Render(writer)
End Sub
protected override void OnPreRender(EventArgs e)
{
    if (!this.DesignMode)
    {
        // Test for ScriptManager and register if it exists
        sm = ScriptManager.GetCurrent(Page);

        if (sm == null)
            throw new HttpException("A ScriptManager control must exist on the current page.");

        sm.RegisterScriptControl(this);
    }

    base.OnPreRender(e);
}

protected override void Render(HtmlTextWriter writer)
{
    if (!this.DesignMode)
        sm.RegisterScriptDescriptors(this);

    base.Render(writer);
}

下面的示例演示 Web 服务器控件的完整代码。

Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Collections.Generic

Namespace Samples.VB

    Public Class SampleTextBox
        Inherits TextBox
        Implements IScriptControl

        Private _highlightCssClass As String
        Private _noHighlightCssClass As String
        Private sm As ScriptManager

        Public Property HighlightCssClass() As String
            Get
                Return _highlightCssClass
            End Get
            Set(ByVal value As String)
                _highlightCssClass = value
            End Set
        End Property

        Public Property NoHighlightCssClass() As String
            Get
                Return _noHighlightCssClass
            End Get
            Set(ByVal value As String)
                _noHighlightCssClass = value
            End Set
        End Property

        Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
            If Not Me.DesignMode Then

                ' Test for ScriptManager and register if it exists
                sm = ScriptManager.GetCurrent(Page)

                If sm Is Nothing Then _
                    Throw New HttpException("A ScriptManager control must exist on the current page.")

                sm.RegisterScriptControl(Me)
            End If

            MyBase.OnPreRender(e)
        End Sub

        Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
            If Not Me.DesignMode Then _
              sm.RegisterScriptDescriptors(Me)

            MyBase.Render(writer)
        End Sub

        Protected Overridable Function GetScriptReferences() As IEnumerable(Of ScriptReference)
            Dim reference As ScriptReference = New ScriptReference()
            reference.Path = ResolveClientUrl("SampleTextBox.js")

            Return New ScriptReference() {reference}
        End Function

        Protected Overridable Function GetScriptDescriptors() As IEnumerable(Of ScriptDescriptor)
            Dim descriptor As ScriptControlDescriptor = New ScriptControlDescriptor("Samples.SampleTextBox", Me.ClientID)
            descriptor.AddProperty("highlightCssClass", Me.HighlightCssClass)
            descriptor.AddProperty("nohighlightCssClass", Me.NoHighlightCssClass)

            Return New ScriptDescriptor() {descriptor}
        End Function

        Function IScriptControlGetScriptReferences() As IEnumerable(Of ScriptReference) Implements IScriptControl.GetScriptReferences
            Return GetScriptReferences()
        End Function

        Function IScriptControlGetScriptDescriptors() As IEnumerable(Of ScriptDescriptor) Implements IScriptControl.GetScriptDescriptors
            Return GetScriptDescriptors()
        End Function
    End Class
End Namespace
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;

namespace Samples.CS
{
    public class SampleTextBox : TextBox, IScriptControl
    {
        private string _highlightCssClass;
        private string _noHighlightCssClass;
        private ScriptManager sm;

        public string HighlightCssClass
        {
            get { return _highlightCssClass; }
            set { _highlightCssClass = value; }
        }

        public string NoHighlightCssClass
        {
            get { return _noHighlightCssClass; }
            set { _noHighlightCssClass = value; }
        }

        protected override void OnPreRender(EventArgs e)
        {
            if (!this.DesignMode)
            {
                // Test for ScriptManager and register if it exists
                sm = ScriptManager.GetCurrent(Page);

                if (sm == null)
                    throw new HttpException("A ScriptManager control must exist on the current page.");

                sm.RegisterScriptControl(this);
            }

            base.OnPreRender(e);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if (!this.DesignMode)
                sm.RegisterScriptDescriptors(this);

            base.Render(writer);
        }

        protected virtual IEnumerable<ScriptReference> GetScriptReferences()
        {
            ScriptReference reference = new ScriptReference();
            reference.Path = ResolveClientUrl("SampleTextBox.js");

            return new ScriptReference[] { reference };
        }

        protected virtual IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            ScriptControlDescriptor descriptor = new ScriptControlDescriptor("Samples.SampleTextBox", this.ClientID);
            descriptor.AddProperty("highlightCssClass", this.HighlightCssClass);
            descriptor.AddProperty("nohighlightCssClass", this.NoHighlightCssClass);

            return new ScriptDescriptor[] { descriptor };
        }

        IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
        {
            return GetScriptReferences();
        }

        IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
        {
            return GetScriptDescriptors();
        }
    }
}

创建客户端控件

在 Web 服务器控件中,GetScriptReferences 方法指定一个 JavaScript 文件 (SampleTextBox.js),此文件包含针对控件类型的客户端代码。本节描述该文件中的 JavaScript 代码。

客户端控件代码与由 GetScriptDescriptors 方法返回的 ScriptDescriptor 对象中指定的成员匹配。客户端控件也可包含与 Web 服务器控件类中的成员不对应的成员。

示例 Web 服务器控件将客户端控件的名称设置为 Samples.SampleTextBox,并定义客户端控件的两个属性:highlightCssClass 和 nohighlightCssClass。

有关如何创建客户端组件和控件的更多信息,请参见使用原型模型创建客户端组件类

注册客户端命名空间

客户端控件代码必须首先调用 Type 类的 registerNamespace 方法来为注册其命名空间 (Samples)。下面的示例演示如何注册客户端命名空间。

// Register the namespace for the control.
Type.registerNamespace('Samples');

定义客户端类

在注册客户端命名空间之后,代码将定义 Samples.SampleTextBox 类。此类包括两个用于保留由 Web 服务器控件提供的属性值的属性。它还包括两个事件委托,用于指定与 Samples.SampleTextBox 控件关联的 DOM 元素的 onfocus 和 onblur 事件的处理程序。

下面的示例演示 Samples.SampleTextBox 类定义。

Samples.SampleTextBox = function(element) { 
    Samples.SampleTextBox.initializeBase(this, [element]);

    this._highlightCssClass = null;
    this._nohighlightCssClass = null;
}

定义类原型

定义 Samples.SampleTextBox 类之后,客户端代码将定义该类的原型。此原型包括属性的 get 和 set 访问器以及事件处理程序。它还包括 initialize 方法(当创建该控件的实例时将调用此方法)和 dispose 方法(当页不再需要该控件时,此方法将执行清理)。

定义 DOM 元素的事件处理程序

将客户端类的事件处理程序定义为类原型的方法。通过使用 addHandlers 方法将处理程序与事件委托和浏览器 DOM 的事件相关联,在本主题后面的部分会将此方法与 initialize 方法一起讨论。

下面的示例演示 Samples.SampleTextBox 控件的事件处理程序方法。

_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;          
    }
},

定义属性 Get 和 Set 方法

在 Web 服务器控件的 GetScriptDescriptors 方法的 ScriptDescriptor 对象中标识的每个属性都必须具有相应的客户端访问器。将客户端属性访问器定义为客户端类原型的 get_<property name> 和 set_<property name> 方法。

Bb386450.alert_note(zh-cn,VS.90).gif说明:

JavaScript 区分大小写。get 和 set 访问器名称必须与 Web 服务器控件中的 GetScriptDescriptors 方法的 ScriptDescriptor 对象中标识的属性名称完全匹配。

下面的示例演示 Samples.SampleTextBox 控件的属性 get 和 set 访问器。

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 和 Dispose 方法

在创建控件的实例时将调用 initialize 方法。使用此方法可设置默认属性值、创建函数委托以及将委托添加为事件处理程序。

Samples.SampleTextBox 类的 initialize 方法执行以下操作:

  • 调用 Sys.UI.Control 基类的 initialize 方法。

  • 调用 addHandlers 方法以将事件委托添加为关联的 HTML 元素 (<input type="text">) 的 onfocus 和 onblur 事件的处理程序。不指定事件名称的“on”部分(例如,onfocus)。

当不再在页上使用该控件的实例并将其删除时,将调用 dispose 方法。使用此方法可释放该控件不再需要的任何资源(例如,DOM 事件处理程序)。

Sample.SampleTextBox 类的 dispose 方法执行以下操作:

  • 调用 clearHandlers 方法以清理作为关联的 DOM 元素的 onfocus 和 onblur 事件的处理程序的事件委托。

  • 调用 Control 基类的 dispose 方法。

    Bb386450.alert_note(zh-cn,VS.90).gif说明:

    可能会多次调用客户端类的 dispose 方法。确保您在 dispose 方法中包括的代码已考虑到上述情况。

下面的示例演示 Samples.SampleTextBox 原型的 initialize 和 dispose 方法的实现。

initialize : function() {
    Samples.SampleTextBox.callBaseMethod(this, 'initialize');

    this._onfocusHandler = Function.createDelegate(this, this._onFocus);
    this._onblurHandler = Function.createDelegate(this, this._onBlur);

    $addHandlers(this.get_element(), 
                 { 'focus' : this._onFocus,
                   'blur' : this._onBlur },
                 this);

    this.get_element().className = this._nohighlightCssClass;
},

dispose : function() {
    $clearHandlers(this.get_element());

    Samples.SampleTextBox.callBaseMethod(this, 'dispose');
},

注册控件

客户端控件创建过程中的最后任务是通过调用 registerClass 方法为客户端类注册。由于此类是一个客户端控件,因此对 registerClass 方法的调用将包括要注册的 JavaScript 类名称。它还将 Control 指定为基类。

下面的示例演示对 Samples.SampleTextBox 控件的 registerClass 方法的调用。此示例也包括对 Sys.Application 对象的 notifyScriptLoaded 方法的调用。若要通知 Microsoft AJAX Library 已加载 JavaScript 文件,则必须使用此调用。

Samples.SampleTextBox.registerClass('Samples.SampleTextBox', Sys.UI.Control);

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

下面的示例演示 Samples.SampleTextBox 客户端控件的完整代码。

// Register the namespace for the control.
Type.registerNamespace('Samples');

//
// Define the control properties.
//
Samples.SampleTextBox = function(element) { 
    Samples.SampleTextBox.initializeBase(this, [element]);

    this._highlightCssClass = null;
    this._nohighlightCssClass = null;
}

//
// Create the prototype for the control.
//

Samples.SampleTextBox.prototype = {


    initialize : function() {
        Samples.SampleTextBox.callBaseMethod(this, 'initialize');

        this._onfocusHandler = Function.createDelegate(this, this._onFocus);
        this._onblurHandler = Function.createDelegate(this, this._onBlur);

        $addHandlers(this.get_element(), 
                     { 'focus' : this._onFocus,
                       'blur' : this._onBlur },
                     this);

        this.get_element().className = this._nohighlightCssClass;
    },

    dispose : function() {
        $clearHandlers(this.get_element());

        Samples.SampleTextBox.callBaseMethod(this, 'dispose');
    },

    //
    // Event delegates
    //

    _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;          
        }
    },


    //
    // Control properties
    //

    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');
        }
    }
}

// Optional descriptor for JSON serialization.
Samples.SampleTextBox.descriptor = {
    properties: [   {name: 'highlightCssClass', type: String},
                    {name: 'nohighlightCssClass', type: String} ]
}

// Register the class as a type that inherits from Sys.UI.Control.
Samples.SampleTextBox.registerClass('Samples.SampleTextBox', Sys.UI.Control);

if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

动态编译该控件以进行测试

任何 Web 服务器控件(例如,本主题中的控件)必须先经过编译,然后才能在网页上进行引用。可使用 ASP.NET 2.0 版的动态编译功能来测试 Web 服务器控件,而无需手动将该控件编译到程序集中。在最初编写和调试 Web 服务器控件代码时,这将为您节省时间。下面的步骤演示如何使用 App_Code 文件夹来动态编译控件。

将控件放入 App_Code 文件夹中以进行动态编译

  1. 在网站的根文件夹下,创建一个 App_Code 文件夹。

  2. 将 .cs 或 .vb 控件源文件和任何相关类移动到 App_Code 文件夹中。

    - 或 -

    如果先前已将控件的程序集添加到 Bin 文件夹中,请删除此程序集。继续编辑 App_Code 文件夹中的源文件。每当运行项目时,都将编译控件源代码。

    Bb386450.alert_note(zh-cn,VS.90).gif说明:

    可以将一个控件预编译到一个程序集中,并将该程序集置于 Bin 文件夹中,也可以将该控件的源文件置于 App_Code 文件夹中,但不能同时执行这两种操作。如果将此控件同时添加到这两个文件夹中,则页分析器将无法解析对页中控件的引用,并将引发错误。

  3. 运行网页。

    将动态编译该控件。

在网页上测试动态编译的控件

下面的过程描述如何在支持 AJAX 的 ASP.NET 网页上测试控件。从 App_Code 文件夹中动态编译 Web 服务器控件的代码。

在 ASP.NET 页上使用行为

  1. 创建一个新的 ASP.NET 网页。

  2. 如果此页还没有 ScriptManager 控件,请添加一个此类控件。

  3. 为突出显示的文本框和未突出显示的文本框分别创建 CSS 样式规则。

    可以按照您喜欢的任何方式突出显示控件。例如,可以更改控件的背景色、添加边框或更改文本的字体。

  4. 在页中添加 @ Register 指令,然后指定控件的命名空间和 TagPrefix 属性,如以下示例所示。

    Bb386450.alert_note(zh-cn,VS.90).gif说明:

    在本例中,服务器控件代码位于 App_Code 文件夹中,以便能够动态编译。因此,不指定程序集属性。

  5. 在页中添加 TextBoxButton 控件,并设置其 ID 属性。

    控件的标记必须包含 runat="server"。

  6. 将 FocusExtender 控件的实例添加到页中。

  7. 将 FocusExtender 控件的 TargetControlID 属性设置为先前添加的 Button 控件的 ID。

  8. 将 HighlightCssClass 属性设置为突出显示的 CSS 样式,并将 NoHighlightCssClass 属性设置为不突出显示的 CSS 样式。

  9. 运行页并选择每个控件。

    当选择 Button 控件时,该控件将突出显示。

下面的示例演示一个 ASP.NET 页,此页使用本主题中创建的行为。

将控件编译为程序集

将 JavaScript 组件和 Web 服务器控件的扩展代码嵌入到一个程序集中将使您的自定义控件更易于部署。创建程序集也使您能够更轻松地管理控件的版本控制。此外,除非将控件编译到程序集中,否则不能将这些控件添加到设计器的工具箱中。

下面的过程描述如何使用 Visual Studio 在现有的主题项目中创建新的代码库。将代码文件的副本移动到本主题的项目中的新代码库中。在代码库中编译控件将得到一个可部署的程序集。

Bb386450.alert_note(zh-cn,VS.90).gif说明:

若要执行此过程,必须使用 Microsoft Visual Studio 2005。不能使用 Visual Web Developer 2005 速成版,因为 Visual Web Developer 速成版不允许您在同一解决方案中创建两个项目。

将新代码库添加到现有项目中

  1. 在 Visual Studio 中的**“文件”菜单上,单击“新建”,然后单击“项目”**。

    将显示**“新建项目”**对话框。

  2. 在**“项目类型”下,选择“Visual C#”“Visual Basic”**。

  3. 在**“模板”下,选择“类库”**,然后将项目命名为“Samples”。

  4. 在**“解决方案”列表中,选择“添加到解决方案”,然后单击“确定”**。

    将 Samples 类库添加到现有解决方案中。

将自定义服务器控件移动到代码库中

  1. 将下面的引用添加到 Samples 类库项目,这些引用是自定义服务器控件所必需的:

    • System.Drawing

    • System.Web

    • System.Web.Extensions

  2. 在**“解决方案资源管理器”**中,复制来自原始项目的 SampleTextBox.cs 或 SampleTextBox.vb 文件和 SampleTextBox.js 文件,然后将复制的文件添加到 Samples 类库项目的根目录中。

  3. 在 SampleTextBox.js 文件对应的**“属性”窗口中,将“生成操作”设置为“嵌入的资源”**。

    将脚本文件设置为嵌入式资源

  4. 将下面的属性添加到 AssemblyInfo 文件中。

    <Assembly: WebResource("Samples.SampleTextBox.js", "text/javascript")>
    
    [assembly: System.Web.UI.WebResource("Samples.SampleTextBox.js", "text/javascript")]
    
    Bb386450.alert_note(zh-cn,VS.90).gif说明:

    AssemblyInfo.vb 文件位于解决方案资源管理器的“我的项目”节点上。如果在“我的项目”节点中未看到任何文件,请执行以下操作:在“项目”菜单上单击“显示所有文件”。AssemblyInfo.cs 文件位于解决方案资源管理器的“属性”节点上。

    JavaScript 文件的 WebResource 定义必须遵循 [程序集命名空间].[JavaScript 文件名].js 的命名约定。

    Bb386450.alert_note(zh-cn,VS.90).gif说明:

    默认情况下,Visual Studio 将程序集命名空间设置为程序集名称。可以在程序集属性中编辑程序集命名空间。

  5. 在 SampleTextBox 类文件中,更改 GetScriptReferences 方法中的 ScriptReference 对象以引用“Samples”程序集中嵌入的客户端控件脚本。为此,请进行以下更改:

    • Path 属性替换为设置为“Samples”的 Assembly 属性。

    • 添加 Name 属性并将其值设置为“Samples.SampleTextBox.js”。

    下面的示例演示此更改的结果。

            Protected Overridable Function GetScriptReferences() As IEnumerable(Of ScriptReference)
                Dim reference As ScriptReference = New ScriptReference()
                reference.Assembly = "Samples"
                reference.Name = "Samples.SampleTextBox.js"
    
                Return New ScriptReference() {reference}
            End Function
    
            protected virtual IEnumerable<ScriptReference> GetScriptReferences()
            {
                ScriptReference reference = new ScriptReference();
                reference.Assembly = "Samples";
                reference.Name = "Samples.SampleTextBox.js";
    
                return new ScriptReference[] { reference };
            }
    
  6. 生成项目。

    完成编译后,将得到一个名为 Samples.dll 的程序集。将 JavaScript 代码文件 (SampleTextBox.js) 作为资源嵌入此程序集中。

    Bb386450.alert_note(zh-cn,VS.90).gif说明:

    请记住,只要添加新的资源文件或更改现有资源文件,就应重新生成类库项目。

在网页中使用其程序集中已编译的控件

现在,您将在支持 AJAX 的 ASP.NET 网页中引用已编译的自定义控件。

在支持 AJAX 的 ASP.NET 网页中引用自定义控件

  1. 创建新的 ASP.NET AJAX 项目。

  2. 在网站的根目录中创建一个 Bin 文件夹。

  3. 将 Samples.dll 程序集从 Samples 类项目的 Bin\Debug 或 Bin\Release 文件夹中复制到新的 Bin 文件夹。

  4. 添加名为 TestSampleTextBoxAssembly.aspx 的新 ASP.NET 网页,然后将以下标记添加到新页。

    <%@ Register Assembly="Samples" Namespace="Samples.VB" TagPrefix="sample" %>
    
    <%@ Register Assembly="Samples" Namespace="Samples.CS" TagPrefix="sample" %>
    

    由于已将服务器控件编译到程序集中,因此除 Namespace 和 TagPrefix 属性之外,@ Register 指令还具有一个引用“Samples”程序集的 Assembly 属性。

  5. 运行页并选择每个控件。

    当选择 SampleTextBox 控件时,该控件将突出显示。

使用已编译的自定义控件的网页在 @ Register 指令中包含 Assembly 属性。除此之外,此网页与用于 App_Code 文件夹中的控件的网页相同。

请参见

概念

创建扩展程序控件以将客户端行为与 Web 服务器控件关联

将 ASP.NET UpdatePanel 控件与数据绑定控件一起使用

参考

Sys.UI.Control 类

IScriptControl

ScriptManager