复合控件的创建
创建定制控件的第三种方法是组合二个或二个以上的现有的控件。在下面的例子中,读者将以合同编程人员的身份出现,而我则是客户,我希望读者能够开发一个稍微复杂一些的控件,使我能够用来记录收到的对我的书的询价。
作为客户,我将要求读者开发一个控件,使我能够输入一本或多本书籍,每当点击一本书时,控件就会记录下对该书的点击次数,如下图所示:
这一程序的.aspx文件如下所示,除@ Page命令外,该程序的C#和VB程序是相同的:
利便控件的.aspx文件
<%@ Page language="c#"
Codebehind="WebForm1.aspx.cs"
AutoEventWireup="false"
Inherits="CustomControlWebPage.WebForm1" %>
<%@ Register TagPrefix="OReilly" Namespace="CustomControls" Assembly="CustomControls"
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<meta content="Microsoft Visual Studio 7.0" name=GENERATOR>
<meta content=C# name=CODE_LANGUAGE>
<meta content="JavaScript (ECMAScript)" name=vs_defaultClientScript>
<meta content=http://schemas.microsoft.com/intellisense/ie5 name=vs_targetSchema>
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id=Form1 method=post runat="server">
<OReilly:BookInquiryList
Runat="Server"
id="bookInquiry1">
<OReilly:BookCounter
Runat="server"
BookName="Programming ASP.NET"
ID="Bookcounter1"/>
<OReilly:BookCounter
Runat="server"
BookName="Programming C#"
ID="Bookcounter2" />
<OReilly:BookCounter
Runat="server"
BookName="Teach Yourself C++ 21 Days"
ID="BookCounter3" />
<OReilly:BookCounter
Runat="server"
BookName="Teach Yourself C++ 24 Hours"
ID="Bookcounter4" />
<OReilly:BookCounter
Runat="server"
BookName="Clouds To Code"
ID="Bookcounter5" />
<OReilly:BookCounter
Runat="server"
BookName="C++ From Scratch"
ID="Bookcounter6" />
<OReilly:BookCounter
Runat="server"
BookName="Web Classes From Scratch"
ID="Bookcounter7" />
<OReilly:BookCounter
Runat="server"
BookName="XML Web Documents From Srcatch"
ID="Bookcounter8" />
</OReilly:BookInquiryList>
</FORM>
</body>
</HTML>
在上面的代码中需要注意的是,BookInquiryList组件中包含许多BookCounter元素,其中有一个BookCounter元素是对应着我希望记录的书籍。这个控件非常灵活,我可以对任意数量的书进行记录。每个BookCounter元素有一个用来显示被记录书籍名字的BookName属性。
从图9中我们可以看到,每本书都由一个CountedButton定制控件进行记录,但.aspx文件中没有CountedButton控件的定义,它被完整地封装在了BookCounter定制控件中。
整个体系结构如下所示:
BookInquiry利便控件是由WebControl派生的,实现了INamingContainer,在下面我们会提到。
BookInquiry控件有一个由Control类派生的Controls特性。
在控件集合中有数量不等的BookCounter控件。
BookCounter本身也是一个由WebControl派生得来的复合控件,WebControl也实现了INamingContainer。
BookContainer的每个实例有二个特性:BookName和Count。
Name特性是由Viewstate支持的,而且通过.aspx文件中的BookName BookName初始化。
Count特性授权给private性质的CountedButton对象
使用BookInquiry对象的目的有二个:它是BookCounter对象的容器;它负责绘制它本身并确保它包含的BookCounter对象能够按需求绘制自己。
CountedButton控件的修改
我们需要对CountedButton控件进行一些很小的修改,下面分别是C#和VB.NET版的CountedButton控件。
修改后的CountedButton.cs文件
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace CustomControls
{
// 由System.Web.UI.WebControls.Button派生出的定制控件
public class CountedButton : System.Web.UI.WebControls.Button
{
private string displayString;
// 缺省的构造器
public CountedButton( )
{
displayString = "clicks";
InitValues( );
}
// 重载,显示字符串
public CountedButton(string displayString)
{
this.displayString = displayString;
InitValues( );
}
// 由构造器调用的函数
private void InitValues( )
{
if (ViewState["Count"] == null)
ViewState["Count"] = 0;
this.Text = "Click me";
}
// Count是ViewState中的一个特性
public int Count
{
get
{
// 在构造器中初始化,不能是NULL
return (int) ViewState["Count"];
}
set
{
ViewState["Count"] = value;
}
}
// 覆盖OnClick事件处理程序,增大Count变量的值,并在更新按钮上的文本后调用基础类中的方法
protected override void OnClick(EventArgs e)
{
ViewState["Count"] = ((int)ViewState["Count"]) + 1;
this.Text = ViewState["Count"] + " " + displayString;
base.OnClick(e);
}
}
}
修改后的CountedButton.vb文件
Imports System.ComponentModel
Imports System.Web.UI
Imports System.Web.UI.WebControls
' 从System.Web.UI.WebControls.Button中派生的定制控件
Public Class CountedButton
Inherits System.Web.UI.WebControls.Button
Private displayString As String
' 构造器对ViewState进行初始化
Public Sub New( )
displayString = "clicks"
Init( )
End Sub
' 重载,显示字符串
Public Sub New(ByVal displayString As String)
Me.displayString = displayString
Init( )
End Sub
' 由构造器调用的方法
Private Shadows Sub Init( )
If ViewState("Count") = Is Nothing Then
ViewState("Count") = 0
Me.Text = "Click me"
End If
End Sub
' Count是ViewState中的一个特性
Public Property Count( ) As Integer
Get
Return CInt(ViewState("Count"))
End Get
Set(ByVal Value As Integer)
ViewState("Count") = Value
End Set
End Property
' 覆盖OnClick事件处理程序,增大Count变量的值,并在更新按钮上的文本后调用基础类中的方法
Protected Overrides Sub OnClick(ByVal e As EventArgs)
ViewState("Count") = CInt(ViewState("Count")) + 1
Me.Text = CStr(ViewState("Count") & "
" & displayString
MyBase.OnClick(e)
End Sub
End Class?)
由于我们希望按钮上显示“5 Inquiries”而不是“5 clicks”字符串,因此必须修改OnClick方法中修改按钮字符串文本的代码:
this.Text = ViewState["Count"] + " " + displayString;
相应的VB.NET代码是:
Me.Text = ViewState("Count") & " " & displayString
我们还使用了一个private性质的成员变量displayString来存储传递给构造器中的数值:
private string displayString;
在VB.NET中的代码为:
Private displayString As String
我们必须在构造器中设置这一字符串。为了保护已经使用了缺省的构造器的代码,我们必须重载构造器,新增加一个带有字符串参数的构造器:
public CountedButton(string displayString)
{
this.displayString = displayString;
Init( );
}
在VB.NET中的代码是:
Public Sub New(ByVal displayString As String)
Me.displayString = displayString
Initialize( )
End Sub
我们可以对缺省的构造器进行修改,将displayString成员变量有值设置为一个合理的缺省值。其C#代码如下:
public CountedButton( )
{
displayString = "clicks";
InitValues( );
}
相应的VB.NET代码是:
Public Sub New( )
displayString = "clicks"
Init( )
End Sub
二个构造器的代码都没有考虑private性质的辅助方法Init,它能够保证Count特性被初始化为0,并设置最初时按钮显示的字符串:
private void Init( )
{
if (ViewState["Count"] == null)
ViewState["Count"] = 0;
this.Text = "Click me";
}
在VB.NET中,相应的代码为:
Private Shadows Sub Init( )
If ViewState("Count") = Nothing Then
ViewState("Count") = 0
Me.Text = "Click me"
End If
End Sub
作了上述的修改后,我们就可以在第一个复合控件━━BookCounter中使用CountedButton了。
BookCounter复合控件的创建
BookCounter复合控件用于记录和显示对某一本书查询的次数,下面分别是C#和VB.NET版的BookCounter复合控件的源代码:
C#版本的BookCounter控件源文件:BookCounter.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace CustomControls
{
public class BookCounter :
System.Web.UI.WebControls.WebControl,
INamingContainer
{
// 初始化按钮成员
CountedButton btn = new CountedButton("inquiries");
public string BookName
{
get
{
return (string) ViewState["BookName"];
}
set
{
ViewState["BookName"] = value;
}
}
public int Count
{
get
{
return btn.Count;
}
set
{
btn.Count = value;
}
}
public void Reset( )
{
btn.Count = 0;
}
protected override void CreateChildControls( )
{
Controls.Add(btn);
}
}
}
VB.NET版的BookCounter控件的源代码: BookCounter.vb
Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.ComponentModel
Public Class BookCounter
Inherits System.Web.UI.WebControls.WebControl
Implements INamingContainer
' 初始化按钮成员
Public btn As CountedButton = New CountedButton("inquiries")
Public Property BookName( ) As String
Get
Return CStr(ViewState("BookName"))
End Get
Set(ByVal Value As String)
ViewState("BookName") = Value
End Set
End Property
Public Property Count( ) As Integer
Get
Return btn.Count
End Get
Set(ByVal Value As Integer)
btn.Count = Value
End Set
End Property
Public Sub Reset( )
btn.Count = 0
End Sub
Protected Overrides Sub CreateChildControls( )
Controls.Add(btn)
End Sub
End Class
标签:
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com