第二章(3)自定义控件

来源:互联网 发布:oa系统 mac 编辑:程序博客网 时间:2024/06/01 17:46

摘要:asp.net中提供的增加内嵌服务器控件的功能,使你能够多次的轻松增加你所定义的各种控件。事实上,对于表单等各种控件,可以不用更改或者稍微更改一下就可以多次使用的。在通常情况下,我们把一个用作服务器控件的web表单统称为用户控件,我们用一个.ascx为后缀的文件保存起来,这样的保存使得它不被当作一个web表单来运行。

ASP.NET基础教程-第二章 (3)自定义控件

asp.net中提供的增加内嵌服务器控件的功能,使你能够多次的轻松增加你所定义的各种控件。事实上,对于表单等各种控件,可以不用更改或者稍微更改一下就可以多次使用的。在通常情况下,我们把一个用作服务器控件的web表单统称为用户控件,我们用一个.ascx为后缀的文件保存起来,这样的保存使得它不被当作一个web表单来运行,当我们在一个.aspx文件中使用它时,我们用Register方法来进行调用,假设我们有一个文件名为saidy.ascx的文件,我们用下面的语句来调用它:

<%@ Register TagPrefix="Acme" TagName="Message" Src="saidy.ascx" %>
上面的TagPrefix标记为用户控件确定个唯一的名字空间,TagName为用户控件确定一个唯一的名称,你也可以用其它的名字代替"Message",Src为确定所包含的文件名称和路径。这样,我们就可以用下面的语句来调用它了:

<Acme:Message runat="server"/>

下面我们来看看具体的应用
2.3.1 小页面控件
我们建立两个简单文件来说明这个控件的使用方法:con01.aspx、con01.ascx,在con01.ascx文件里我们只有一句话:
<a href="http://www.yesky.com">欢迎访问天极网站</a>

然后我们在文件con01.aspx里面进行注册:

<%@ Register TagPrefix="saidy" TagName="info" Src="con01.ascx" %>

页面上的应用我们用这句话来表达:

<saidy:info runat="server"/>

con01.aspx文件的完整代码如下:

<!--源文件:form\CustomControl\con01.aspx-->
<!--注册小页面控件-->
<%@ Register TagPrefix="saidy" TagName="info" Src="con01.ascx" %>
<html>
<body>
<BR><BR><BR>
<CENTER>
调用结果
<BR><BR>
<saidy:info runat="server"/>
</CENTER>
<BR><BR>
</body>
</html>
下面我们访问con01.aspx,显示如下:

2.3.2 代码和模板的分离
在编制asp.net程序时,我们会使用模板(Template)。那么什么是模板呢?相信大家都使用过WORD,当我们在新建一个WORD文件的时候,我们可以建立模板。通过使用模板,我们就固定了文档的风格,这样就可以在模板上完善我们的内容。所以我们使用模板一个好处是:文字录入和编排界面是分开的。而且模板可以重复使用。好了,通过上面的介绍,我们对模板就有了一定的认识。 我们在编制.NET程序时,使用模板将对主程序代码大大简化。模板的定义是使用<template>和</template>标示符的。文件保存为.ascx文件。下面的代码是一个典型的模板的定义。

<template name="itemtemplate">
<table cellpadding=10 style="font: 10pt verdana">
<tr>
<td >
<b>所在系: </b><%# DataBinder.Eval(Container.DataItem, "dept") %><br>
<b>姓名: </b><%# DataBinder.Eval(Container.DataItem, "name") %><br>
<b>性别: </b><%# DataBinder.Eval(Container.DataItem, "sex") %><br>
<b>年级: </b><%# DataBinder.Eval(Container.DataItem, "grade") %>
</td>
</tr>
</table>
</template>

在这一模板中,我们使用了数据绑定控件,关于数据绑定控件,请参阅其它章节。同时我们还定义了数据的显示方式。那么在主程序中如何调用呢?请看下面的代码:

1. <%@ Register TagPrefix="Acme" TagName="StuList" Src="form32.ascx" %>
2. <html>
3. <body style="font: 10pt verdana">
4. <b><center><h3>模板示例</h3></center></b>
5. <form runat="server">
6. <Acme: StuList runat="server"/>
7. </form>
8. </body>
9. </html>

其实,模板也属于自定义控件(User Control),所以我们在使用时,要先注册(Register)。对主程序的第一行代码,TagPrefix定义了一个不重复的名字空间(Name Space)。TagName为自定义控件定义了一个名称。然后,我们就要指明使用的模板的文件名。注册完自定义控件后,我们就可以把此控件认为是服务器端控件。要使用服务器端控件,我们要做什么工作呢?对了,要使用runat="server"属性了。请参考第7行代码。
好了,现在我们就看一个完整的例子!这个例子包含了两个文件,一个主程序文件(template.aspx),另一个是用户自定义控件文件(template.ascx)。先看template.aspx文件。
<!--源文件:form\CustomControl\template.aspx-->
<%@ Register TagPrefix="Acme" TagName="stuList" Src="zy.ascx" %>
<html>
<body style="font: 10pt verdana">
<b><center><h3>模板示例</h3></center></b>
<form runat="server">
<Acme:stuList runat="server"/>
</form>
</body>
</html>
现在我们再来看template.ascx:
<!--源文件:form\CustomControl\template.ascx-->
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SQL" %>
<script language="VB" runat="server">
Sub Page_Load(Src As Object, E As EventArgs)
If Not (Page.IsPostBack)
Dim DS As DataSet
Dim MyConnection As SQLConnection
Dim MyCommand As SQLDataSetCommand
MyConnection = New SQLConnection("server='iceberg';uid=sa;pwd=;database=info")
MyCommand = New SQLDataSetCommand("select * from infor where dept='" & Category.SelectedItem.Value & "'", MyConnection)
DS = New DataSet()
MyCommand.FillDataSet(DS, "infor")
MyDataList.DataSource = DS.Tables("infor").DefaultView
MyDataList.DataBind()
End If
End Sub

Sub Category_Select(Sender As Object, E As EventArgs)
Dim DS As DataSet
Dim MyConnection As SQLConnection
Dim MyCommand As SQLDataSetCommand
MyConnection = New SQLConnection("server='iceberg';uid=sa;pwd=;database=info")
MyCommand = New SQLDataSetCommand("select * from infor where dept='" & Category.SelectedItem.Value & "'", MyConnection)
DS = New DataSet()
MyCommand.FillDataSet(DS, "infor")
MyDataList.DataSource = DS.Tables("infor").DefaultView
MyDataList.DataBind()
End Sub
</script>
<table style="font: 10pt verdana">
<center>
<tr>
<center><td><b>请选择系名:</b></td></center>
<td style="padding-left:15">
<center> <ASP:DropDownList AutoPostBack="true" id="Category" OnSelectedIndexChanged="Category_Select" runat="server">
<ASP:ListItem value="信息系">信息系</ASP:ListItem>
<ASP:ListItem value="工程系">工程系</ASP:ListItem>
<ASP:ListItem value="英语系">英语系</ASP:ListItem>
</ASP:DropDownList></center>

</td>
</tr>
</table>
<ASP:DataList id="MyDataList" BorderWidth="0" RepeatColumns="2" runat="server">
<template name="itemtemplate">
<table cellpadding=10 style="font: 10pt verdana">
<tr>
<td >
<b>所在系: </b><%# DataBinder.Eval(Container.DataItem, "dept") %><br>
<b>姓名: </b><%# DataBinder.Eval(Container.DataItem, "name") %><br>
<b>性别: </b><%# DataBinder.Eval(Container.DataItem, "sex") %><br>
<b>年级: </b><%# DataBinder.Eval(Container.DataItem, "grade") %>
</td>
</tr>
</center>
</table>
</template>
</ASP:DataList>
运行的效果图如下:

这样,一个完整的例子就做好了!实现了代码和模板的分离。试一下吧!

2.3.3 自定义控件
在asp.net中,除了我们应用的服务端控件之外,我们还可以创建自己的服务端控件,这样的控件叫Pagelet。我们来介绍如何创建一个Pagelet,这个Pagelet的功能是在被访问时返回一个消息。

我们创建一个Pagelet,用来返回一个消息在客户端的浏览器上:
Welcome.ascx:
<!--源文件:form\CustomControl\welcome.ascx-->
欢迎来到我这里啊!!!

就这么简单,当然你也可以让它复杂一点。当一个Pagelet被创建后,我们就可以通过下面的记录指示来调用它:

<% @ Register TagPrefix="wmessage" TagName="wname" Src="Welcome.ascx" %>

TagPrefix为Pagelet指定一个唯一的名字空间,TagName是Pagelet的唯一名字,当然你也可以换成其他的不是"wname"的名称如:TagName="saidy"。Src属性是指指向Pagelet的虚拟路径。

一旦我们注册了Pagelet,我们就可以向用普通的空件一样来应用它:

<wmessage:wname runat="server"/>

下面的例子示范了自定义的控件的应用(welcome.aspx):
<!--源文件:form\CustomControl\welcome.aspx-->
<%@ Register TagPrefix="wmessage" TagName="wname" Src="Welcome.ascx" %>
<html>
<title>自定义的控件</title>
<h3>.NET->Pagelet</h3>
<wmessage:wname runat="server"/>
</body>
</html>

客户端的访问如下:

2.3.4 组合控件
1.定义
以类组合形式把已有的控件编译后形成自己定制的控件。实际上组合控件在效果上与利用内置控件形成的用户自定义控件一样,不同处在于,用户自定义控件含有一个.ascx的纯文本控制文件,而组合控件则利用编译后的代码。
2.步骤
1.)重新定义从Control继承来的CreateChildControls方法。
2.)如果组合控件要保持于页面上,须完成System.Web.UI.INamingContainer 接口。
3.例子:
演示一个自定义控件,当选择不同按钮时显示不同内容。
1)控件定义

'文件名:form\CustomControl\FormCustom.vb
Option Strict Off

Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace test
'定义类tryVB
Public Class tryVB : Inherits Control : Implements INamingContainer
'定义属性value,实为TextBox控件的Text属性
Public Property value As String
Get
Dim Ctrl As TextBox = Controls(1)
Return Ctrl.text
End Get

Set
Dim Ctrl As TextBox = Controls(1)
Ctrl.Text = value
End Set
End Property

Protected Overrides Sub CreateChildControls()
'重载CreateChildControls方法
Me.Controls.Add(New LiteralControl("选择结果为: "))

Dim Box As New TextBox
Box.Text = " "
Me.Controls.Add(box)

End Sub

End Class

End Namespace

2)定义控件的编译

:批处理文件form\CustomControl\FormCustom.bat的内容:
vbc /t:library /out:..\bin\testVB.dll /r:System.dll /r:System.Web.dll FormCustom.vb

请注意把生成的testVB.dll放到正确的目录中,以便asp.net解释时能够找到相应的类。

3)自定义组合控件的使用

<!--源文件:form\CustomControl\formcustom.aspx-->
<%@ Register TagPrefix="test" Namespace="test" %>
<!--首先注册test命名空间-->
<html>
<script language="VB" runat=server>
Private Sub LeftBtn_Click(Sender As Object, E As EventArgs)
'当选择左边的按钮时的显示
CustControl.Value = "您选择的是Yes按钮"
End Sub
Private Sub RightBtn_Click(Sender As Object, E As EventArgs)
'当选择右边的按钮时的显示
CustControl.value = "您选择的是No按钮"
End Sub

</script>

<body>
<center>
<form method="POST" action="formcustom.aspx" runat=server>
<!--引用自定义的组合控件tryVB-->
<test:tryVB id="CustControl" runat=server/>
<br>
<!--画两个按钮供选择-->
<asp:button text="是[Yes]" OnClick="LeftBtn_Click" runat=server/>
<asp:button text="否[No]" OnClick="RightBtn_Click" runat=server/>
</form>
</center>
</body>
</html>

输出结果:

2.3.5 继承控件
在学习了微软公司的.NET平台为我们提供的大量功能强大的服务器端控件的使用方法以后,随着应用的深入,一些新的问题又出现了。首先是虽然有着大量的控制灵活的控件,但是否就真的满足了我们所有的需求?有时候,我们需要某种控件部分功能,又希望不要费太大的力气去实现,是否可以利用现有的控件来实现。再则,我们希望对某种控件进行改造,使它具有自己所希望的外形或者结果,而不是它缺省的方式运行。最后我们是否可以把自己经常用到的逻辑规则或者是应用界面作成用户控件,然后使用它就如同使用服务器控件那样方便。
其实以上三个问题,在现代面向对象设计方法中,是可以找到答案的。为最大可能的利用现有的开发成果,我们使用"继承"这一手段来节省开发的费用。光有继承不足以形成自己的应用,我们还可以利用"重载"和"多态"来形成自己的应用特点,使之区别于被继承的对象。为了使应用更加简洁和对外隐藏内部的实现、进一步实现代码重用,我们又使用了"封装"。
微软的.NET平台是支持面向对象的设计方式的新型平台,所以支持并且鼓励用户在应用中设计和使用自己定义的控件。设计用户自己的控件就如同上面所述,有如下步骤:

1. 从System.Web.UI.Control类继承,并形成自己的类
为继承Control类,我们需引用System、System.Web、System.Web.UI类库,在vb环境下使用标识Imports来引入。为方便使用,我们还需定义一个命名空间以容纳多个类。在vb环境中使用Namespace 空间名和End Namespace标识对来定义一个命名空间。定义一个类使用Class ClassName和End Class标识对。为表明类之间的继承关系,可以使用Inherits标识。
继承控件的类定义框架定义如下:
Imports System
Imports System.Web
Imports System.Web.UI

Namespace MyNamespace
Public Class MyClass:Inherits Control

End Class
End Namespace

一个最简单的例子是从Control继承一个类,然后重载其Render方法。调用其Render方法即在页面以h2字体写出一行字。
Imports System
Imports System.Web
Imports System.Web.UI

Namespace MyNamespace
Public Class MyClass:Inherits Control

Protect overrides Sub Render(OutPut as HtmlTextWriter)
OutPut.Write("<h2>这是一个最简单的控件继承例子!</h2>")
End Sub
End Class
End Namespace

2. 定义自己的属性和方法,包括重载一些初始化的方法。
在vb中,以标识overrides指明该方法是一个重载函数。例如上面所举的Render方法:Protect overrides Sub Render(Output as HtmlTextWriter)

属性定义就较为复杂一点,首先是定义内部变量,可以为Public或者是Private,当为Public时可以被外部直接存取,这种方式面向对象方法并不提倡,为Private时,不能直接被外部存取,只有通过内部提供的属性定义方式来存取;然后对需要提供给外部使用的内部变量进行属性存取方式定义。在vb中使用Property 属性名 As 类型和End Property标识对来定义,Get/End Get标识对间定义如何通过属性取得内部变量的值,Set/End Set标识对间定义如何设置内部变量值。

例如:描述一个人的帐号信息,大致需要设定帐号(AcctNo)、身份证号(IdNo)、余额(Balance)、有效状态(Stat)
Imports System
Imports System.Web
Imports System.Web.UI

Namespace MyNamespace
'定义一个枚举变量,0-正常 1-销户 2-其他状态(挂失、冻结等等)
Public Enum Status
Active = 0
Deactive = 1
Other = 2
End Enum

Public Class Account : Inherits Control

Private _AcctNo As String
Private _IdNo As String
Private _Balance As Currency
Private _Stat As Status

Public Property AcctNo As String
Get
Return _AcctNo
End Get
Set
_AcctNo = Value
End Set
End Property

Public Property IdNo As String
Get
Return _IdNo
End Get
Set
_IdNo = Value
End Set
End Property

Public Property Balance As Currency
Get
Return _Balance
End Get
Set
_Balance = Value
End Set
End Property

Public Property Stat As Status
Get
Return _Stat
End Get
Set
_Stat = Value
End Set
End Property

End Class

End Namespace

而方法的定义就比较灵活,可以根据设计要求,提供相应的功能,例如大多数的类一般都会提供创建或者是初始化类的方法。我们仍以上面的帐号类为例,定义一个New方法:
。。。
Public Sub New(AcctNo1 As String,IdNo1 As String,Balance1 As Currency,Stat1 As Status)
MyBase.New
Me.AcctNo = AcctNo1
Me.IdNo = IdNo1
Me.Balance = Balance1
Me.Stat = Stat1
End Sub
。。。

3.定义自己应用界面
一个用户自定义的控件一般来说较为复杂,由至少一个以上的内置控件构成,这时就需要重载从Control类继承来的CreateChildControls方法,并在其中生成界面控件。如果用户定义的控件会在一个页面中反复使用,最好implements System.Web.UI.INamingContainer,它会为该控件创建一个唯一的命名空间。

例如:下面的例子将创建一个控件,它由一段说明文字和一个文本输入框构成。
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace MyNamespace
Public Class Myclass :Inherits Control : Implements INamingContainer

Protected Overrides Sub CreateChildControls()

Me.Controls.Add(New LiteralControl("<h3>请输入: "))

Dim txtBox As New TextBox
txtBox.Text = ""
Me.Controls.Add(txtBox)

Me.Controls.Add(New LiteralControl("</h3>"))
End Sub

End Class
End Namespace

4. 定义自己控件的消息处理函数。
自己定义的控件含有两种类型的消息,一是包含的子控件所产生的消息,二是自定义的控件消息。
子控件产生的消息处理函数可由AddHandler函数来指定,其用法如下:
AddHandler 子控件.消息,AddressOf 消息处理函数
例如:自定义控件中含有一个Button控件,并定义其处理函数MyBtn_Click()

Private Sub MyBtn_Click(Sender as Objects, E as EventArgs)

End Sub

Protected override Sub CreateChildControls()

Dim MyBtn As New Button
MyBtn.text=""
AddHandler MyBtn.Click , AddressOf MyBtn_Click
Me.Controls.Add(MyBtn)

End Sub

自定义的控件消息则需要先定义事件说明,格式如下
Public Event 消息名(Sender as Object,E as EventArgs)
例如:Public Event Change(Sender as Object,E as EventArgs)
然后定义事件发出函数,例如:
Protected Sub OnChange(E as EventArgs)
RaiseEvent Change(Me,E)
End Sub
再然后定义引起事件发生的过程(可不写)
例如:
Private Sub TextBox_Change(Sender As Object, E As EventArgs)
OnChange(EventArgs.Empty)
End Sub
最后定义何时触发事件函数,同样使用AddHandler函数
例如:

Protected override Sub CreateChildControls()

Dim MyBox as New TextBox
MyBox.Text=""
AddHandler MyBox.TextChanged , AddressOf TextBox_Change
Me.Controls.Add(MyBox)

End Sub

5. 最后,谈一谈继承控件的使用,首先应把预先写好的继承控件编译成.DLL文件
编译格式为:
vbc /t:library /out:MyDll.dll /r:System.Web.dll MyVb.vb
vbc为vb.net的编译器
/t:表示编译类型,library为链接库,exe为独立可执行文件
/out:指定输出文件名
/r:表示需要引用的DLL文件
MyVb.vb:指自己编写的继承控件vb源程序

然后,为在自己的页面中引用自己定义的控件,需在aspx文件头进行注册,
<%@ Register TagPrefix="标记前缀" Namespace="命名控件" %>
最后,就如同使用内置控件一样,在页面中使用自己定义的控件:
<命名空间名:类名 …… runat=server />

 


下面举一个具体的例子来说明:
我们仍然以开始定义的用户帐号为例来定义一个继承控件,该类有4个属性分别为客户帐号、身份证号、帐户余额、帐户状态,其用户界面设定为4个文本框供输入属性值以供修改,另外加2个按钮以供确认,同时为该控件设定一个事件Click,当按下确认键后,修改控件属性值,并且在页面中显示自定义控件的属性值,以确认事件确实生效了。

1. 控件定义文件

'文件名:form\CustomControl\Inherit.vb
Option Strict Off

Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace MyNamespace

Public Enum Status
Active = 0
Deactive = 1
Other = 2
End Enum

Public Class MyAccount:Inherits Control:Implements INamingContainer
'从Control类继承,并且有自己的命名空间
Private _AcctNo As String
Private _IdNo As String
Private _Balance As Decimal
Private _Stat As Status

Public Event Click(Sender as Object,E as EventArgs)
'定义控件自身的Click事件

'对属性存取的定义
Public Property AcctNo As String
Get
Return _AcctNo
End Get
Set
_AcctNo = Value
End Set
End Property

Public Property IdNo As String
Get
Return _IdNo
End Get
Set
_IdNo = Value
End Set
End Property

Public Property Balance As Decimal
Get
Return _Balance
End Get
Set
_Balance = Value
End Set
End Property

Public Property Stat As Status
Get
Return _Stat
End Get
Set
_Stat = Value
End Set
End Property

Public Sub New()
MyBase.New
Me.AcctNo = ""
Me.IdNo = ""
Me.Balance = "0.0"
Me.Stat = "0"
End Sub

Protected Sub OnClick(E as EventArgs)
RaiseEvent Click(Me,E)
End Sub

'界面定义为4个属性文本输入框,加一个确定和取消键
Protected Overrides Sub CreateChildControls()
Me.Controls.Add(New LiteralControl("<h3>客户帐号:"))
dim txtAcctNo as New TextBox
txtAcctNo.text=_AcctNo
Me.Controls.Add(txtAcctNo)

Me.Controls.Add(New LiteralControl("<br>身份证号:"))
dim txtIdNo as New TextBox
txtIdNo.text=_IdNo
Me.Controls.Add(txtIdNo)

Me.Controls.Add(New LiteralControl("<br>帐户余额:"))
dim txtBalance as New TextBox
txtBalance.text=_Balance
Me.Controls.Add(txtBalance)

Me.Controls.Add(New LiteralControl("<br>帐户状态:"))
dim txtStat as New TextBox
txtStat.text=_Stat
Me.Controls.Add(txtStat)

Me.Controls.Add(New LiteralControl("<br><br><br>"))
dim Btn1 as New Button
Btn1.text="确 认"
AddHandler Btn1.Click,AddressOf Btn1_Click
Me.Controls.Add(Btn1)

dim Btn2 as New Button
Btn2.text="取 消"
Me.Controls.Add(Btn2)

Me.Controls.Add(New LiteralControl("</h3>"))
End Sub

Private Sub Btn1_Click(Sender as Object,E as EventArgs)
dim ctrl1 as TextBox=controls(1)
Me.AcctNo=ctrl1.text
dim ctrl2 as TextBox=controls(3)
Me.IdNo=ctrl2.text
dim ctrl3 as TextBox=controls(5)
Me.Balance=CDbl(ctrl3.text)
dim ctrl4 as TextBox=controls(7)
Me.Stat=Cint(ctrl4.text)
OnClick(E)
End Sub

End Class

End Namespace


2. 控件编译文件

rem inherit.vb 的编译文件 文件名:form\CustomControl\i.bat
vbc /t:library /out:.\bin\MyNamespaceVB.dll /r:System.Web.dll inherit.vb

3. 页面使用文件

<!--源文件:form\CustomControl\FormInherit.aspx-->
<%@ Register TagPrefix="MyNamespace" Namespace="MyNamespace" %>
<html>
<script language="vb" runat=server>
sub acct_click(s as object, e as eventargs)
dim strTxt as string
strTxt="<hr>AcctNo="& acct1.AcctNo & "<br>"
strTxt=strTxt & "IdNo=" & acct1.IdNo & "<br>"
strTxt=strTxt & "Balance=" & acct1.Balance & "<br>"
strTxt=strTxt & "Stat=" & acct1.Stat
response.write(strTxt)
end sub
</script>
<head>
<title>
继承控件实验
</title>
</head>

<body bgcolor=#ccccff>
<center>
<h2>继承控件MyAccount的使用</h2>
<hr>
<br>
<form action="forminherit.aspx" method="post" runat=server>
<MyNamespace:MyAccount id="acct1" AcctNo="1234" IdNo="5678" OnClick="acct_click" runat=server />
</form>
</center>
</body>
</html>

4.开始的输出画面:

5.修改后,按确认键后的效果:

2.3.6小结

本章在前一章学习了服务器端控件的基础上,探讨了如何在利用已有控件的基础上,开发具有自己特色的自定义控件。使用自定义控件的好处在于:
1. 简化了自己程序开发的周期
2. 有助于形成具有自己特色的风格
3. 隔离了错误发生的根源,修改自己定义的控件时,不必考虑其他因素

转自:http://www.lezhu99.com/5.html

0 0
原创粉丝点击