http://blog.csdn.net/zzmdegm/article/details/1588705
在进行Web开 发时通常会出现这样的情况:即可用的工具的功能虽然强大,但不符合具体项目的需求,可能是给定控件的工作方式并不像所期望的那样,也可能是一部分代码本来 的目的是能够在多个页上重用,但是许多开发人员实现起来却相当复杂。在这些情况下,定制控件的建立就尤为迫切。简言之,定制控件可以把多个现有的控件包装 在一起,这些现有控件还可能有指定布局的额外属性;定制控件也可以与现有的控件完全不同。使用定制控件与使用ASP.NET中的控件一样简单,能使Web站点的编码非常容易。
在过去,实现定制控件是非常复杂的,尤其在大型系统中,由于使用定制控件需要复杂的注册过程,因此定制控件的实现就更为复杂。即使在简单的系统上,创建定制控件所需进行的编码也是一个相当复杂的过程。老版本Web语言的脚本编码功能也不能对手工编写的对象模型提供较好地访问,因此各个方面的性能都比较差。
.NET Framework使用简单的编程技术,为定制控件的创建提供了一个理想的设置。ASP.NET服务器控件的每个方面都可以随意定制,包括模板制作、客户端脚本编码等功能。但是,也不必为所有这些功能编写代码;控件越简单,创建就越容易。
另外,.NET系统中固有的程序集动态查询使Web应用程序在新Web服务器上的安装如同复制包含代码的目录结构一样简单。要使用自己创建的控件,只需复制包含这些控件的程序集和其他代码即可。甚至可以把频繁使用的控件放在Web服务器上一个位于全局程序集缓存器(GAC)的程序集中,这样服务器上所有的Web应用程序就可以访问它们了。
本章将介绍两类不同的控件:
● 用户控件——即把现有的ASP.NET页转化为控件
● 定制控件——即组合几个控件的功能、扩展现有的控件以及从头创建新的控件
我们将创建一个简单的控件,显示一副扑克牌(黑桃、方块、红桃和梅花),以便轻松地把它嵌入到其他ASP.NET页面中,以此来阐明用户控件的用法。对于定制控件,则创建一个投票控件,它允许用户在列表中选择一个候选人进行投票,并查看投票过程。
27.1 用户控件
用户控件是用ASP.NET代码创建的控件,就像在标准的ASP.NET Web页面中创建控件一样,不同之处在于一旦创建了用户控件,就可以在多个ASP.NET页面中重用它们。
例如,假定已经创建了一个显示数据库中信息的页面,信息也许是关于订单的,就不必创建一个固定的页面去显示信息,而是可以把相关的代码放到用户控件中,然后把该控件插入到任意多个不同的Web页面中。
此外,可以给用户控件定义属性和方法,例如,可以指定Web页面上显示数据库表时的背景色属性,或者指定一个方法,重新进行数据库查询以检查数据库中的变化。
下面创建一个简单的用户控件,与其他章节一样,本章的示例项目也可以从Wrox网站www.wrox.com上下载。
一个简单的用户控件
在VS.NET中,创建一个新Web应用程序PCSUserCWebApp1。一旦生成标准文件,就可以选择Project | Add New Item菜单选项,添加名称为PCSUserC1.ascx的Web用户控件,如图27-1所示。
图 27-1
给项目添加的文件的扩展名为.ascx和.ascx.cs,它们的工作方式与前面的.aspx文件非常相似。.ascx文件将包含ASP.NET代码,看起来与普通的.aspx文件非常相似。.ascx.cs文件是代码后置文件,它定义了用户控件,定义的方式与在.aspx.cs文件中定义窗体的方式一样。
与.aspx文件相似,也可以在设计或HTML视图中查看.ascx文件。在HTML视图中查看文件,可以发现一个重要的区别:.ascx文件没有显示HTML代码,特别是没有<form>元素,原因在于:用户控件要插入到其他文件的ASP.NET窗体中,因此不需要自己的窗体标记。生成的代码如下所示。
<%@ Control Language="c#" AutoEventWireup="false" Codebehind="PCSUserC1.ascx.cs"
Inherits="PCSUserCWebApp1.PCSUserC1"
TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
这非常类似于在.aspx文件中生成的<%@ Page %>指令,但指定了Control,而不是Page,并包括一个TargetSchema属性。这个属性指定控件是为哪个浏览器创建的。在本例中是Internet Explorer 5,这会影响可以从VS.NET工具箱中添加的项目。
查看.aspx.cs文件中生成的代码,可以发现另一个与ASP.NET页面的重要区别:所生成的类是从System.Web.UI.UserControl继承来的。这也是因为控件将用在窗体中,控件并不是窗体。
本例的简单控件是一个显示图形的控件,显示的图形对应于扑克牌中的一种花色(即梅花、方块、红桃和黑桃)。这里所需的图形是VS.NET附带的图形;它们在C:/Program Files/Microsoft Visual Studio .NET 2003/Common7/Graphics/bitmaps/assorted目录中,其文件名分别是CLUB.BMP、DIAMOND.BMP、HEART.BMP和SPADE.BMP。把这些图形文件复制到项目目录中,以便在后面使用它们。
给新控件添加一些代码。在PCSUserC1.ascx的HTML视图中添加下列代码:
<%@ Control Language="c#" AutoEventWireup="false" Codebehind="PCSUserC1.ascx.cs"
Inherits="PCSUserCWebApp1.PCSUserC1"
TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<table cellspacing=4>
<tr valign="middle">
<td>
<asp:Image Runat="server" ID="suitPic" ImageURL="club.bmp"/>
</td>
<td>
<asp:Label Runat="server" ID="suitLabel">Club</asp:Label>
</td>
</tr>
</table>
这段代码定义了控件的默认状态,即一个梅花图形和一个标签。在给控件添加额外功能之前,首先把这个控件添加到项目的Web页面WebForm1.aspx上,测试这个默认状态。
为了在.aspx文件中使用定制的控件,首先需要指定如何引用该控件,也就是说,如何在HTML中引用代表控件的标记名称。为此,在代码的最前面使用<%Register%>指令,如下所示。
<%@ Register TagPrefix="PCS" TagFTEL="UserC1" Src="PCSUserC1.ascx" %>
属性TagPrefix和TagName指定要使用的标记名称(指定的格式为<TagPrefix:TagName>),使用属性Src指向包含用户控件的文件。现在,添加下面的元素,就可以使用控件了:
<form id="Form1" method="post" runat="server">
<PCS:UserC1 Runat="server" ID="myUserControl"/>
</form>
在窗体的后台编码文件中,用户控件没有在默认状态下声明,因此也需要给WebForm1.aspx.cs添加下面的声明:
public class WebForm1 : System.Web.UI.Page
{
//申明一个用户控件
protected PCSUserCWebApp1.PCSUserC1 myUserControl;
...
这就是测试用户控件所需要做的所有工作,运行项目的结果如图27-2所示。
图 27-2
可以看出,这个控件组合了两个现有的控件,即图形控件和标签控件,因此它属于合成控件一类。
为了控制显示的花色图形,可以在元素<PCS:UserC1>上使用属性。用户控件元素上的属性会自动映射到用户控件的特性上,因此,只需给控件的后台编码PCSUserC1.ascx.cs添加特性。这个特性称为Suit,让它接收合适的花色值。为了便于表示控件的状态,在PCSUserC1.ascx.cs文件中定义命名空间PCSUserCWebApp1中的一个枚举,以保存4个花色名称:
namespace PCSUserCWebApp1
{
...
public enum suit
{
club, diamond, heart, spade
}
...
}
类PCSUserC1需要一个成员变量,以保存花色类型currentSuit:
public class PCSUserC1 : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.Image suitPic;
protected System.Web.UI.WebControls.Label suitLabel;
protected suit currentSuit;
再添加一个访问这个成员变量的属性Suit:
public suit Suit
{
get
{
return currentSuit;
}
set
{
currentSuit = value;
suitPic.ImageUrl = currentSuit.ToString() + ".bmp";
suitLabel.Text = currentSuit.ToString();
}
}
这里的set存取器把图形的URL设置为前面复制的一个文件,并把要显示的文本设置为花色名称。
下面需要给WebForm1.aspx添加代码以访问这个新的属性。使用刚才添加的属性选择花色:
<PCS:UserC1 Runat="server" id="myUserControl" Suit="diamond"/>
ASP.NET处理器可以从提供的字符串中选择出正确的枚举项。但为了使该控件更有趣、更吸引人,下面使用一个单选按钮列表来选择花色:
<form id="Form1" method="post" runat="server">
<PCS:UserC1 Runat="server" ID="myUserControl"/>
<asp:RadioButtonList Runat="server" ID="suitList"
AutoPostBack="True">
<asp:ListItem Value="club" Selected="True">Club</asp:ListItem>
<asp:ListItem Value="diamond">Diamond</asp:ListItem>
<asp:ListItem Value="heart">Heart</asp:ListItem>
<asp:ListItem Value="spade">Spade</asp:ListItem>
</asp:RadioButtonList>
</form>
还需要给列表的SelectedIndexChanged事件添加事件处理程序。双击设计视图中的单选按钮列表,就可以添加处理程序。
注意:
把列表的autopostback属性设置为true,是因为除非进行回送操作,否则将不在服务器上执行suitList_SelectedIndexChanged事件处理程序,在默认状态下,这个控件也不会触发回送 操作。
在WebForm1.aspx.cx中,方法suitList_SelectedIndexChanged()需要以下代码:
protected void suitList_SelectedIndexChanged(object sender,
System.EventArgs e)
{
myUserControl.Suit = (suit)Enum.Parse(typeof(suit),
suitList.SelectedItem.Value);
}
我们知道,元素<ListItem>上的value属性代表前面定义的枚举suit的有效值,因此简单地把这些值解析为枚举类型,并把它们用作用户控件的Suit属性值。使用简单的数据类型转换语法,就可以把返回的对象类型转换为suit,因为这个类型不能通过隐式转换而得到。
在运行Web应用程序时,可以改变花色,如图27-3所示。
图 27-3
接下来,给控件添加一些方法。这是非常简单的,只需给PCSUserC1类添加方法就可以了:
public void Club()
{
Suit = suit.club;
}
public void Diamond()
{
Suit = suit.diamond;
}
public void Heart()
{
Suit = suit.heart;
}
public void Spade()
{
Suit = suit.spade;
}
4个方法Club()、Diamond()、Heart()和Spade()分别用于改变显示在屏幕上的扑克牌的花色。
在.aspx页面上的4个ImageButton控件上调用这些函数:
</asp:RadioButtonList>
<asp:ImageButton Runat="server" ID="clubButton"
ImageUrl="CLUB.BMP"
OnClick="clubButton_Click"/>
<asp:ImageButton Runat="server" ID="diamondButton"
ImageUrl="DIAMOND.BMP"
OnClick="diamondButton_Click"/>
<asp:ImageButton Runat="server" ID="heartButton"
ImageUrl="HEART.BMP"
OnClick="heartButton_Click"/>
<asp:ImageButton Runat="server" ID="spadeButton"
ImageUrl="SPADE.BMP"
OnClick="spadeButton_Click"/>
</form>
事件处理程序如下:
protected void clubButton_Click(object sender,
System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Club();
suitList.SelectedIndex = 0;
}
protected void diamondButton_Click(object sender,
System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Diamond();
suitList.SelectedIndex = 1;
}
protected void heartButton_Click(object sender,
System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Heart();
suitList.SelectedIndex = 2;
}
protected void spadeButton_Click(object sender,
System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Spade();
suitList.SelectedIndex = 3;
}
既然有了4个新按钮,就可以改变扑克牌的花色,如图27-4所示。
图 27-4
完成了用户控件的创建后,使用<%@Register%>指令和为控件创建的两个源代码文件(PCSUserC1.ascx和PCSUserC1.ascx.cs),就可以在其他的Web页面中使用这个用户控件了。
下面是完整项目代码:
用户控件:PCSUSerC1.ascx
<%@ Control Language="c#" AutoEventWireup="false" Codebehind="PCSUSerC1.ascx.cs" Inherits="PCSUserCWebApp1.PCSUSerC1" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<table cellspacing="4">
<tr valign="middle">
<td>
<asp:Image id="suitPic" runat="server" ImageUrl="pic/CLUB.BMP"></asp:Image></td>
<td>
<asp:Label id="suitLabel" runat="server">Club</asp:Label></td>
</tr>
</table>
图像为:
图 27-5
PCSUSerC1.ascx.cs
namespace PCSUserCWebApp1
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
/// <summary>
/// PCSUSerC1 的摘要说明。
/// </summary>
public class PCSUSerC1 : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.Image suitPic;
protected System.Web.UI.WebControls.Label suitLabel;
protected suit currentSuit;
private void Page_Load(object sender, System.EventArgs e)
{
// 在此处放置用户代码以初始化页面
}
public enum suit{CLUB,DIAMOND,HEART,SPADE}
//控件的属性和方法的定义
public suit Suit{
get{return currentSuit;}
set{
currentSuit=value;
this.suitPic.ImageUrl="pic/"+currentSuit.ToString()+".bmp";
this.suitLabel.Text=currentSuit.ToString();
}
}
public void Club(){Suit=suit.CLUB;}
public void Diamond(){Suit=suit.DIAMOND;}
public void Heart(){Suit=suit.HEART;}
public void Spade(){Suit=suit.SPADE;}
WebForm1.aspx(页面调用)
<!-- 注册一个用户控件-->
<%@ Register TagPrefix="PCS" TagName="UserC1" Src="PCSUserC1.ascx"%>
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="PCSUserCWebApp1.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" 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">
用户控件:<br>
<PCS:USERC1 id="myUserControl" runat="server" Suit="DIAMOND"></PCS:USERC1><br><hr>
使用系统控件对用户控件的操作:<br>
<asp:ImageButton id="IB_DIAMOND" runat="server" ImageUrl="pic/DIAMOND.BMP"></asp:ImageButton>
<asp:ImageButton id="IB_SPADE" runat="server" ImageUrl="pic/SPADE.BMP"></asp:ImageButton>
<asp:ImageButton id="IB_HEART" runat="server" ImageUrl="pic/HEART.BMP"></asp:ImageButton>
<asp:ImageButton id="IB_CLUB" runat="server" ImageUrl="pic/CLUB.BMP"></asp:ImageButton></form>
</body>
</HTML>
页面图片为:
图 27-6
后台代码:WebForm1.aspx(页面调用)
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using PCSUserCWebApp1;
namespace PCSUserCWebApp1
{
/// <summary>
/// WebForm1 的摘要说明。
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.ImageButton IB_DIAMOND;
protected System.Web.UI.WebControls.ImageButton IB_SPADE;
protected System.Web.UI.WebControls.ImageButton IB_HEART;
protected System.Web.UI.WebControls.ImageButton IB_CLUB;
//申明一个用户控件
protected PCSUserCWebApp1.PCSUSerC1 myUserControl;
private void Page_Load(object sender, System.EventArgs e)
{
// 在此处放置用户代码以初始化页面
//用户控件属性取得
string a=myUserControl.Suit.ToString();
}
//用户控件方法的调用
private void IB_HEART_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Heart();
}
private void IB_SPADE_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Spade();
}
private void IB_CLUB_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Club();
}
private void IB_DIAMOND_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
myUserControl.Diamond();
}