创作自定义控件

阅读:530次   时间:2008-03-06 00:00:00   字体:[ ]

创作自定义控件

 

 


本“入门”节说明高级开发人员可以如何编写他们自己的在 ASP.NET 页框架中工作的 ASP.NET 服务器控件。通过编写自己的自定义 ASP.NET 服务器控件,可以封装可在 ASP.NET 页上重用的控件中的自定义用户界面和其他功能。“入门”通过实际操作的示例提供关于如何创作自定义控件的介绍。有关控件创作的更多信息,请参阅“Microsoft .NET 框架 SDK”文档中的“开发 ASP.NET 服务器控件”。

注意:本节介绍的控件虽然在运行时可以在 ASP.NET 页上正常工作,但是在设计时可能无法在窗体设计器(如 Microsoft Visual Studio .NET)中正常工作。为了能在设计器中工作,控件需要应用此处未说明的设计时属性。有关需要应用的设计时属性的详细信息,请参阅 SDK 文档中的“组件的设计时属性”。

开发简单的自定义控件
定义简单属性

定义类属性

检索内部内容

开发复合控件

在复合控件中处理事件

从复合控件引发自定义事件

维护状态

开发处理回发数据的自定义(非复合)控件

为自定义回发生成客户端 JavaScrip

开发模板控件

开发模板数据绑定控件

重写控件分析
检索内部内容中看到的,如果控件 A 在页上的其控件标记中有嵌套控件,页分析器会将那些控件的实例添加到 A 的 Controls 集合。这通过调用 A 的 AddSubParsedObject 方法来实现。每个控件从 Control 继承此方法,默认实现只不过将子控件插入到控件层次结构树中。通过重写 AddSubParsedObject 方法,控件可以重写默认的分析逻辑。注意,这里的讨论有些简化,下一个示例给出更多细节。

开始创作您自己的 ASP.NET 服务器控件很容易。创建简单的自定义控件时,您所要做的只是定义从 System.Web.UI.Control 派生的类并重写它的 Render 方法。Render 方法采用 System.Web.UI.HtmlTextWriter 类型的参数。控件要发送到客户端的 HTML 作为字符串参数传递到 HtmlTextWriterWrite 方法。

下面的示例说明呈现消息字符串的简单控件。

 
VB Simple.aspx

[运行示例] | [查看源代码]

 

属性类似具有访问器方法的“聪明”字段。应该从控件公开属性而不是公开公共字段,因为属性允许数据隐藏、可以版本化并受可视化设计器的支持。属性具有设置和检索属性的 get/set 访问器方法,并允许在需要时执行附加的程序逻辑。

下面的示例显示如何添加与基元数据类型(如整型、布尔型和字符串)对应的简单属性。该示例定义三个属性——Message 属于字符串类型,MessageSize 属于枚举类型,Iterations 属于整型类型。注意设置简单属性和枚举属性的页语法。

 
VB SimpleProperty.aspx

[运行示例] | [查看源代码]

 

如果 A 类具有一个类型为 B 类的属性,则 B 的属性(如果有)称为 A 的子属性。下面的示例定义自定义控件 SimpleSubProperty,该控件具有 Format 类型的属性。Format 是具有两个基元属性的类——ColorSize,这两个属性反过来成为 SimpleSubProperty 的子属性。

 
VB SimpleSubProperty.aspx

[运行示例] | [查看源代码]

注意 ASP.NET 具有设置子属性的特殊语法。下面的代码示例显示如何以声明方式设置 SimpleSubProperty 上的 Format.ColorFormat.Size 子属性。“-”语法指示子属性。

<SimpleControlSamples:SimpleSubProperty Message="Hello There" Format-Color="red" Format-Size="3" runat=server/>

 

每个控件都具有从 System.Web.UI.Control 继承的 Controls 属性。这是表示控件的子控件(如果有)的集合属性。如果控件未用 ParseChildrenAttribute 标记,或是标记为 ParseChildrenAttribute(ChildrenAsProperties = false),则当控件在页上以声明方式使用时,ASP.NET 页框架将应用以下分析逻辑。如果分析器在控件的标记内遇到嵌套控件,它将创建嵌套控件的实例并将它们添加到控件的 Controls 属性。标记之间的文本添加为 LiteralControl。任何其他嵌套元素都生成分析器错误。

下面的示例显示自定义控件 SimpleInnerContent。该控件通过检查是否已将 LiteralControl 添加到它的控件集合中,来呈现添加在其标记之间的文本。如果已添加,则它将检索 LiteralControlText 属性,并将其追加到它的输出字符串。

 
VB SimpleInnerContent.aspx

[运行示例] | [查看源代码]

注意:如果自定义控件是从 WebControl 派生的,它将不具有示例中描述的分析逻辑,因为 WebControl 是用 ParseChildrenAttribute(ChildrenAsProperties = true) 标记的,这导致不同的分析逻辑。有关 ParseChildrenAttribute 的更多信息,请参阅 SDK 文档。

 

可以通过使用类撰写组合现有控件来创作新控件。复合控件等效于使用 ASP.NET 页语法创作的用户控件。用户控件和复合控件之间的主要差异是用户控件保持为 .ascx 文本文件,而复合控件则经过编译并保持在程序集中。

开发复合控件的主要步骤是:

  • 重写从 Control 继承的受保护的 CreateChildControls 方法,以创建子控件的实例并将它们添加到控件集合。
  • 如果复合控件的新实例将在页上重复创建,请实现 System.Web.UI.INamingContainer 接口。这是不具有方法的标记接口。当用控件实现时,ASP.NET 页框架将在此控件下创建新的命名范围。这确保了子控件在控件层次结构树中具有唯一的 ID。
因为子控件会提供呈现逻辑,所以不必重写 Render 方法。可以公开合成子控件属性的属性。

下面的示例定义复合控件 Composition1,该控件组合 System.Web.UI.LiteralControlSystem.Web.UI WebControls.TextBoxComposition1 公开一个整数类型的自定义属性 Value,该属性映射到 TextBoxText 属性。

 
VB Composition1.aspx

[运行示例] | [查看源代码]

 

复合控件可以处理其子控件引发的事件。这通过提供事件处理方法,并将委托附加到子控件引发的事件来完成。

下面的示例显示复合控件 Composition2,该控件将两个按钮控件(名为 AddSubtract)添加到上一示例中的复合控件,并为按钮的 Click 事件提供事件处理方法。这些方法增加和减少 Composition2Value 属性。Composition2CreateChildControls 方法创建引用这些方法的事件处理程序(委托)的实例,并将委托附加到 Button 实例的 Click 事件。最后得到一个进行自己的事件处理的控件——单击 Add 按钮时,文本框中的值增加;单击 Subtract 按钮时,值减少。

 
VB Composition2.aspx

[运行示例] | [查看源代码]

 

复合控件可以定义自定义事件,通过引发该事件来响应其子控件引发的事件。

下面的示例显示复合控件 Composition3,该控件引发自定义事件 Change 以响应 TextBox 子控件的 TextChanged 事件。

实现方法如下:

  • 自定义 Change 事件通过标准事件模式定义。(该模式包括受保护的 OnChange 方法的定义,该方法将引发 Change 事件。)

    Public Event Change(Sender as Object, E as EventArgs)
    Protected Sub OnChange(e As EventArgs)
        Change(Me, e)
    End Sub
    C# VB JScript  

     

  • TextBoxTextChanged 事件定义了一个事件处理方法。该方法通过调用 OnChange 方法来引发 Change 事件。

    Private Sub TextBox_Change(sender As Object, e As EventArgs)
        OnChange(EventArgs.Empty)
    End Sub
    C# VB JScript  

     

  • CreateChildControls 方法创建一个事件处理程序的实例,该实例引用上述方法并将事件处理程序附加到 TextBox 实例的 TextChanged 事件。

    Protected Overrides Sub CreateChildControls()
      ...
      Dim box As New TextBox()
      AddHandler Box.TextChanged, AddressOf TextBox_Change
        ...
    End Sub
    C# VB JScript  

     

Change 事件可以由承载控件的页来处理,如下面的示例所示。在此示例中,页为 Change 事件提供事件处理方法。如果用户输入的数字为负,该事件将 Value 属性设置为零。

 
VB Composition3.aspx

[运行示例] | [查看源代码]

 

每个 Web 窗体控件都有一个 State 属性(从 Control 继承),该属性使 Web 窗体控件能够参与 State 管理。State 的类型为 Sytem.Web.UI.StateBag,这是等效于哈希表的数据结构。控件可以将数据作为键/值对保存在 State 中。State 通过 ASP.NET 页框架保持为字符串变量,并以隐藏变量的形式与客户端之间往返。回发时,页框架分析来自隐藏变量的输入字符串,并在页的控件层次结构中填充每个控件的 State 属性。通过使用 State 属性,控件可以还原其状态(将属性和字段设置为它们回发前的值)。控件开发人员应该知道通过往返行程将数据发送到客户端存在性能开销,并且应该明白他们在 State 中保存的内容。

下面的代码示例显示在 State 中保存的属性。

Public Property Text As String
  Get
    Return CType(State("Text"), String))
  End Get
  Set
    State("Text") = Value
  End Set
End Property
C# VB JScript  

下面的示例显示自定义控件Label。该控件具有两个属性 TextFontSize,它们保存于 State 中。使用 Label 的 ASP.NET 页包含具有事件处理程序的按钮。当单击按钮时,该事件处理程序增加 Label 中的文本字体大小。因此,每次单击按钮时,字体大小都增加。这可能只是由于状态管理的缘故——Label 需要在回发前知道字体大小是多少,以便在回发后呈现下一个更大的字体。

 
VB Label.aspx

[运行示例] | [查看源代码]

 

您在本“入门”开始时创作了简单的自定义控件。下面的示例说明一个做更有意义的事情的自定义控件——它呈现输入框,并读入用户输入的数据。检查回发(输入)数据的控件必须实现 System.Web.UI.IPostBackDataHandler 接口。这将向 ASP.NET 页框架发出信号,指出控件应参与回发数据处理。页框架将输入数据作为键/值对传递给此接口的 LoadPostData 方法。在此方法的实现中,控件可以像下面这样检查输入数据并更新其属性。

Private _value As Integer = 0
Public Function LoadPostData(postDataKey As String, values As NameValueCollection) As Boolean
    _value = Int32.Parse(values(Me.UniqueID))
    Return(False)
End Function
C# VB JScript  

下面的示例定义自定义控件 NonComposition1,该控件实现 IPostBackDataHandler 并具有一个 Value 属性。该控件呈现 HTML 输入框,该框的文本属性为 Value 的字符串表示形式。通过检查回发输入数据设置该属性。使用 NonComposition1 的页还具有两个按钮,它们有增加和减少 NonComposition1Value 属性的事件处理程序。

 
VB NonComposition1.aspx

[运行示例] | [查看源代码]

 

如果控件要捕获回发事件(来自客户端的窗体提交),它必须实现 System.Web.UI.IPostBackEventHandler 接口。此接口向 ASP.NET 页框架发出信号,指出控件希望收到回发事件通知。RaisePostBackEvent 方法允许控件处理该事件和引发其他事件。另外,ASP.NET 页框架具有自定义事件结构,该结构允许控件生成启动自定义回发的客户端 JavaScript。回发通常仅由几个元素启动,如 Submit(提交)按钮或 Image(图像)按钮。不过,通过发出客户端 JavaScript,控件也可以从其他 HTML 元素启动回发。

下面的示例定义一个在上一示例 NonComposition1 之上生成的自定义控件 NonComposition2。除了 NonComposition1 提供的接口,它还呈现两个 HtmlButtons,它们生成在单击时导致回发的客户端 JavaScript。这些按钮的名称属性是 Add 和 Subtract。名称属性以字符串参数的形式,通过页框架传递到 RaisePostBackEventNonComposition2 实现 RaisePostBackEvent 以在单击 Add(添加)按钮时增大 Value 属性,而在单击 Subtract(减小)按钮时减小 Value 属性,如下所示。

Public Sub RaisePostBackEvent(eventArgument As String)
    If eventArgument = "Add" Then
        Me.Value = Me.Value + 1
    Else
        Me.Value = Me.Value - 1
    End If
End Sub
C# VB JScript  

显示给客户端的用户界面与上一示例中的相同;不过,整个 UI 由一个也处理回发事件的自定义控件来呈现。页面开发人员只需将 NonComposition2 添加到页,不必提供任何事件处理逻辑。下面的示例显示了此代码的运行。

 
VB NonComposition2.aspx

[运行示例] | [查看源代码]

 

ASP.NET 页框架允许控件开发人员通过使用模板创作将用户界面同控件逻辑分开的控件。通过将 UI 提供为模板标记之间的参数,页面开发人员可以自定义控件的显示。

模板控件具有一个或多个类型为 System.Web.UI.ITemplate 的属性,如下面的示例所示。

Public Property <TemplateContainer(GetType(Template1VB))> MessageTemplate As ITemplate
C# VB JScript  

属性(以上方括号中的)指定容器(父)控件的类型。

ITemplate 接口具有一个方法 InstantiateIn,该方法动态创建控件实例。这在 CreateChildControls 方法中的 ITemplate 属性上调用,如下面的示例所示。

Protected Overrides Sub CreateChildControls()
    If MessageTemplate <> Null Then
        MessageTemplate.InstantiateIn(Me)
    End if
    ...
End Sub
C# VB JScript  

下面的示例显示一个简单的模板控件和使用它的 ASP.NET 页。

 
VB Template1.aspx

[运行示例] | [查看源代码]

 

下面的示例显示用模板创建数据绑定控件的更复杂应用。此示例中定义的 Repeater 控件类似于 System.Web.UI.WebControls.Repeater 控件。

 
VB Repeater1.aspx

[运行示例] | [查看源代码]

下面的示例修改前面的示例,使页使用者可以在回发期间遍历其 Items 集合,以从中取出值。

 
VB Repeater2.aspx

[运行示例] | [查看源代码]

 

正如在

下面的示例定义重写默认分析逻辑的自定义控件 CustomParse1。当分析特定类型的子控件时,它将其添加到集合。CustomParse1 的呈现逻辑基于该集合中的项数。示例中还定义了一个简单的自定义控件 Item

 
VB CustomParse1.aspx

[运行示例] | [查看源代码]

注意:如果自定义控件是从 WebControl 派生的,它将不具有示例中描述的分析逻辑,因为 WebControl 是用 ParseChildrenAttribute(ChildrenAsProperties = true) 标记的,这导致不同的分析逻辑。有关 ParseChildrenAttribute 的更多信息,请参阅 SDK 文档。检索内部内容主题也更详尽地说明了此问题。

 


定义自定义控件生成器

ASP.NET 页框架使用称为控件生成器的类来处理页上控件标记中的声明。每个 Web 窗体控件都与默认的控件生成器类 System.Web.UI.ControlBuilder 关联。默认的控件生成器为它在控件标记中遇到的每个嵌套控件将子控件添加到 Controls 集合。另外,它为嵌套控件标记之间的文本添加 Literal 控件。通过将自定义控件生成器类与控件关联,可以重写此默认行为。这通过对控件应用控件生成器属性来实现,如下面的示例所示。

Public Class <ControlBuilderAttribute(GetType(CustomParse2ControlBuilderVB))> _
  CustomParse2VB : Inherits Control
C# VB JScript  

以上方括号里的元素为公共语言运行库属性,该属性将 CustomParse2ControlBuilder 类与 CustomParse2 控件关联。通过从 ControlBuilder 派生并重写其方法,可以定义您自己的自定义控件生成器。

下面的示例定义一个自定义控件生成器,它重写从 ControlBuilder 继承的 GetChildControlType 方法。此方法返回要添加的控件类型,并可用来决定将要添加哪些控件。在示例中,控件生成器仅在标记名称为“customitem”时才添加子控件。除了添加了自定义属性外,该控件的代码与上一示例非常相似。

 
VB CustomParse2.aspx

[运行示例] | [查看源代码]

 热门文章