在ASP.NET中,我们可以使用CompositeControl类来派生一系统的复合控件,并将其编译到DLL中,以便以后实现控件重用,下面就以Loggin控件为例,对复合控件的开发过程进行说明。
大家如果有什么问题,请给本人发送Email:[email protected]
1. 在VS2010中新建一个项目,选择Web模板,在Web模板中选择ASP.NET Server Control,如下图所示:
2. VS IDE会为我们自动添加一个ServerControl1类,将该文件名以及类名改为Login,如下图所示:
代码中第12行的“DefaultProperty”特性,是指明当该控件被拖放到设计器中,并且被选中时,被控件的默认具备高亮提示的属性是Text属性。
第13行的“ToolboxData”特性,是指明当该控件被拖放到VS的设计器中,在HTML代码视图中所显示的文本内容,为了让该内容中显示的控件名和该控件类的类名相同,将该行代码做如下修改:
[ToolboxData("<{0}:Loggin runat=server>")]
其中是占位符,在最终拖放在设计器中时,会被该控件的命名空间所代替。
第16行的”Bindable”特性,是指明该属性是否可以在绑定设计器可见,true为可见,False为不可见,但是这个时我们仍然可以在ASPX页面里直接将该属性与绑定表达式进行关联,比较手动输入Eval()语句。比如说,我们将该控件放在了一个GridView的模板列里,如果想让该属性绑定到“CustomerID”字段上,如果设置Bindable(true),那么我们可以绑定设计器看到该Text属性,如下图所示:
如果将其设置为false,那么我们就只在ASPX页面中手动编写Eval(“CustomerID”)表达示。
第17行的Category特性,是指将该Text属性应该位于属性窗口的哪一个分组里。上面代码中设置的Category的值是“Appearence”,这就意味着,将该控件拖放到VS的设计器中以后,并查看该控件的属性,如果属性窗口的显示排列方式是按分类方式排列,些时,Text属性就会出现在Appearance分组栏中,如下图所示:
第18行“DefaultValue”特性用来设置该属性的默认值。
第19行“Localizable”特性,是该属性是否可以自动查找本地化资源文件以进行本地化。
3. 前面对代码中的特性类进行了简要的分析,下面我们要对代码进行修改。首先,要想将我们的Login控件变为复合控件,就要将该控件类的基类修改为CompositeControl类,为复合控件中添加子控件,主要是通过重写基类的CreateChildControl方法来实现的,下面代码实现为Login控件添加了控件的功能:
///
/// 用来输入用户名的文本框
///
private TextBox tbxUserName;
///
/// 用来输入密码的文本框
///
private TextBox tbxPassword;
///
/// 用来提交的确认按钮
///
private Button bt;
protected override void CreateChildControls()
{
//清空原有的子控件
this.Controls.Clear();
//初始化新的子控件
this.tbxUserName = new TextBox();
this.tbxPassword = new TextBox();
this.tbxPassword.TextMode = TextBoxMode.Password;
this.bt = new Button();
//注册Button的Click事件
this.bt.Click += new EventHandler(bt_Click);
bt.Text = "log in";
//以Table的方式为这些子控件进行布局
Table table = new Table();
TableCell cell00 = new TableCell();
cell00.Text = "user name:";
TableCell cell01 = new TableCell();
cell01.Controls.Add(this.tbxUserName);
TableRow row0 = new TableRow();
row0.Cells.Add(cell00);
row0.Cells.Add(cell01);
TableCell cell10 = new TableCell();
cell10.Text = "password:";
TableCell cell11 = new TableCell();
cell11.Controls.Add(this.tbxPassword);
TableRow row1 = new TableRow();
row1.Cells.Add(cell10);
row1.Cells.Add(cell11);
TableCell cell20 = new TableCell();
cell20.ColumnSpan = 2;
cell20.Controls.Add(this.bt);
TableRow row2 = new TableRow();
row2.Cells.Add(cell20);
table.Rows.Add(row0);
table.Rows.Add(row1);
table.Rows.Add(row2);
//将新建立的Table添加到子控件的集合中
this.Controls.Add(table);
//通知该控件所以的子控件已经创建完毕
this.ChildControlsCreated = true;
base.CreateChildControls();
}
//当用户登录验证完毕之后触发
public event EventHandler UserLoggedIn;
void bt_Click(object sender, EventArgs e)
{
var conStr = ConfigurationManager.ConnectionStrings["testConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(conStr))
{
var cmd = con.CreateCommand();
cmd.CommandText = "select count(*) from users where uid=@uid and pwd=@pwd";
cmd.Parameters.Add("@uid", SqlDbType.NVarChar, 50).Value = this.tbxUserName.Text;
cmd.Parameters.Add("@pwd", SqlDbType.NVarChar, 50).Value = this.tbxPassword.Text;
con.Open();
int count = (int)cmd.ExecuteScalar();
if (this.UserLoggedIn != null)
{
bool result = count == 0 ? false : true;
this.UserLoggedIn(this, new UserLoggedInEventArgs() { Validated = result });
}
}
}
4. 验证该控件的功能
首先,在解决方案中添加一个网站,然后编译前面的控件库,此时,我们会在工具箱里看到刚才编写的控件,如下图所示:
将其拖动到设计器,如下图所示:
在该控件中我们所添加的自定义事件如下图所示:
5. 由些看来,编写基本的自定义复合控件还是比较简单的,但是我在编写代码的同时,也会发现,由于没有设计器辅助支持,自定义复合控件的界面是一件比较麻烦的事情,程序员只能凭借自己的直观记忆和美工指定的数值化参数来设计。
6. 该控件类的完整代码如下所示:
002 |
using System.Collections.Generic; |
003 |
using System.ComponentModel; |
008 |
using System.Web.UI.WebControls; |
009 |
using System.Configuration; |
010 |
using System.Data.SqlClient; |
013 |
namespace MyControlLib |
015 |
[DefaultProperty( "Text" )] |
016 |
[ToolboxData( "<{0}:Loggin runat=server></{0}:Loggin>" )] |
017 |
public class Loggin : CompositeControl |
019 |
[Description( "this is the event" )] |
020 |
public event EventHandler<UserLoggedInEventArgs> UserLoggedIn; |
026 |
private TextBox tbxUserName; |
030 |
private TextBox tbxPassword; |
035 |
protected override void CreateChildControls() |
038 |
this .Controls.Clear(); |
040 |
this .tbxUserName = new TextBox(); |
041 |
this .tbxPassword = new TextBox(); |
042 |
this .tbxPassword.TextMode = TextBoxMode.Password; |
043 |
this .bt = new Button(); |
045 |
this .bt.Click += new EventHandler(bt_Click); |
049 |
Table table = new Table(); |
050 |
TableCell cell00 = new TableCell(); |
051 |
cell00.Text = "user name:" ; |
052 |
TableCell cell01 = new TableCell(); |
053 |
cell01.Controls.Add( this .tbxUserName); |
055 |
TableRow row0 = new TableRow(); |
056 |
row0.Cells.Add(cell00); |
057 |
row0.Cells.Add(cell01); |
059 |
TableCell cell10 = new TableCell(); |
060 |
cell10.Text = "password:" ; |
061 |
TableCell cell11 = new TableCell(); |
062 |
cell11.Controls.Add( this .tbxPassword); |
064 |
TableRow row1 = new TableRow(); |
065 |
row1.Cells.Add(cell10); |
066 |
row1.Cells.Add(cell11); |
069 |
TableCell cell20 = new TableCell(); |
070 |
cell20.ColumnSpan = 2; |
071 |
cell20.Controls.Add( this .bt); |
072 |
TableRow row2 = new TableRow(); |
073 |
row2.Cells.Add(cell20); |
075 |
table.Rows.Add(row0); |
076 |
table.Rows.Add(row1); |
077 |
table.Rows.Add(row2); |
080 |
this .Controls.Add(table); |
082 |
this .ChildControlsCreated = true ; |
085 |
base .CreateChildControls(); |
088 |
void bt_Click( object sender, EventArgs e) |
090 |
var conStr = ConfigurationManager.ConnectionStrings[ "testConnectionString" ].ConnectionString; |
091 |
using (SqlConnection con = new SqlConnection(conStr)) |
093 |
var cmd = con.CreateCommand(); |
094 |
cmd.CommandText = "select count(*) from users where uid=@uid and pwd=@pwd" ; |
095 |
cmd.Parameters.Add( "@uid" , SqlDbType.NVarChar, 50).Value = this .tbxUserName.Text; |
096 |
cmd.Parameters.Add( "@pwd" , SqlDbType.NVarChar, 50).Value = this .tbxPassword.Text; |
098 |
int count = ( int )cmd.ExecuteScalar(); |
099 |
if ( this .UserLoggedIn != null ) |
101 |
bool result = count == 0 ? false : true ; |
102 |
this .UserLoggedIn( this , new UserLoggedInEventArgs() { Validated = result }); |