http://www.chinaitz.com/html/2009/0307/398750.html
大家好,今天我们来实现一个自定义的控件,之前我们已经知道了,要开发自定义的控件一般继承三个基类:Control,WebControl,还有一个就是今天要说的CompositeControl。
大家也许还记得,之前的开发的控件基本上都是我们自己从头到尾的写一些控件的标记,如<table.....>之类的,而且还有一个大的问题:我们为了使得我们的控件更加的好用,专业,我们还实现了大量的接口,和自己写很多的事件.这样开发控件的时间就加大了。其实我们可以利用ASP.NET中已经有的控件,经过我们包装,实现我们自定义控件。大家可能认为这和用户控件差不多的,但是继承CompositeConytol的控件的自定义控件的灵活性和复用行更好,而且还还添加样式。
还一个更加重要的就是我们不必要实现接口,比如,引发回传的IPostBackEventHandler接口,接受数据的IPostBackDataHandler接口。大家还记得我们之前开发控件中的的那个Button还要申明name为 this.UniqueID ,现在我们都不需要了,因为我们要包装的那些服务器的控件,如TextBox,他们都已经实现了这些。
本章准备开发一个大家都熟知的Login登录控件。
大家先看看效果:
其实分析起来,这个控件是由一些已有的控件组合而成的,分别是:
两个Label,两个TextBox,和一个Button
下面我们就来开发:
首先,还是先继承CompositeControl;
1 publicclassLogin:CompositeControl
然后把就申明我们要组合的控件,如上所说的:
1 #region要组合的控件
2 LabellbUserName;
3 LabellbUserPassward;
4 TextBoxtxtUserName;
5 TextBoxtxtUserPassward;
6 ButtonsubmitButton;
7 #endregion
把控件申明了之后只要初始化,并且将这些控件整合成我们的Login 控件就可以了。这么做呢?
其实开发组合控件很简单,一般只要重写一个方法就可以了。这个方法就是来初始化并且整合那些已经申明了的小控件的。如下:
1 #region重写方法CreateChildControls
2
3 protectedoverridevoidCreateChildControls()
4 {
5 //清空控件,大家可以理解为:初始化一张白纸,好让我们来画画
6
7 Controls.Clear();
8
9 //初始化控件lbUserName
10 lbUserName=newLabel();
11 lbUserName.Text="用户名:";
12 lbUserName.ID="lbUserName";
13 //把控件添加到我们的组合控件中
14 Controls.Add(lbUserName);
15
16 //初始化控件lbUserPassward
17 lbUserPassward=newLabel();
18 lbUserPassward.Text="密 码:";
19 lbUserPassward.ID="lbUserPassward";
20 Controls.Add(lbUserPassward);
21
22 //初始化控件txtUserName
23
24 txtUserName=newTextBox();
25 txtUserName.ID="txtUserName";
26 txtUserName.Width=Unit.Percentage(60);
27 Controls.Add(txtUserName);
28
29 //初始化控件txtUserPassward
30 txtUserPassward=newTextBox();
31 txtUserPassward.ID="txtUserPassward";
32 txtUserPassward.Width=Unit.Percentage(60);
33 Controls.Add(txtUserPassward);
34
35 //初始化控件submitButton
36 submitButton =newButton();
37 submitButton.Text="提交";
38 submitButton.CommandName="Validate";
39 Controls.Add(submitButton);
40
41 告诉编译器,控件已经初始化了
42 ChildControlsCreated=true;
43 }
44 #endregion
大家特别要注意,最后的那句ChildControlsCreated属性,一定要申明,因为在页面的声明周期的任何时候可能调用上面的那个方法,如果不申明ChildControlsCreated,那么这个方法就会被反复的调用,那么我们控件的状态都会丢失。
如果申明了ChildControlsCreated=true,那么这个方法就调用一次。
经过上面的步骤之后,其实我们的控件就已经开发完成了。
可能我们还想进一步的向我们ASP.NET的标准的Login控件靠拢.那么我们的控件还缺少什么?
属性,事件!!!
以前我们定义属性都是用的ViewState["..."],但是这里就不同了。因为我们的控件是有很多的小的控件组合起来的,比如,我们修改“用户名:”的那个Label,我们想改的是那个Label的属性,还是看看效果图:
改前的图: 改后的图
就是说,我们想把子控件的属性如Text,name等等,把这些属性上升呈现为组合控件Login的属性。
怎么做?
也很简单的:如下:
1 publicstringUserNameLabelText
2 {
3 get
4 {
5 EnsureChildControls();
6 returnlbUserName.Text;
7 }
8 set
9 {
10 EnsureChildControls();
11 lbUserName.Text=value;
12 }
13 }
这样我们就把那个显示用户名的Label的Text属性显示为了Login控件的UserNameLabelText属性。大家要注意EnsureChildControls(); 这个方法的调用。其实是个保险的:确保我们要显示属性的那个控件已经创建,已经初始化了。
大家可以根据需要显示更加多的属性。也可以自己定义一些属性,还是像以前那样,可以用ViewState[''.."]
如果到这里为止,就差不多了。大家可以按按照上面的方法来写控件。
大家可以看见,控件的呈现很乱。那些Label.TextBox都布局的很乱。其实你可以根据需要来将上面的那些控件排列的更加好看些,只要重写一个方法就行了:
1protectedoverridevoidRenderContents(HtmlTextWriterwriter)
还是像之前一样,我们想把控件用一个Table来布局,先这样
1 protectedoverrideHtmlTextWriterTagTagKey
2 {
3 get
4 {
5 returnHtmlTextWriterTag.Table;
6 }
7 }
然后再把那些Label,TextBox,Button放到table的行和列中就行了。如下:
1protectedoverridevoidRenderContents(HtmlTextWriterwriter)
2 {
3
4 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
5
6 writer.RenderBeginTag(HtmlTextWriterTag.Td);
7 lbUserName.RenderControl(writer);
8 writer.RenderEndTag();//td的结束
9
10 writer.RenderBeginTag(HtmlTextWriterTag.Td);
11 txtUserName.RenderControl(writer);
12 writer.RenderBeginTag();
13
14 writer.RenderBeginTag();//tr的结束
15
16 //***********************************************
17
18 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
19
20 writer.RenderBeginTag(HtmlTextWriterTag.Td);
21 lbUserPassward.RenderControl(writer);
22 writer.RenderEndTag();//td的结束
23
24 writer.RenderBeginTag(HtmlTextWriterTag.Td);
25 txtUserPassward.RenderControl(writer);
26 writer.RenderBeginTag();
27
28 writer.RenderBeginTag();//tr的结束
29
30 //***********************************************
31
32 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
33
34 writer.AddAttribute(HtmlTextWriterAttribute.Colspan,"2");
35 writer.AddAttribute(HtmlTextWriterAttribute.Align,"center");
36 writer.RenderBeginTag(HtmlTextWriterTag.Td);
37 submitButton.RenderControl(writer);
38 writer.RenderBeginTag();
39
40 writer.RenderBeginTag();//tr的结束
41
42
43
44
45 }
这样,我们的控件就写完了。
我们的控件还差事件。我们在下篇将“事件的冒泡”。
顺便做个调查:大家想看开发控件的视频吗,我正在录制。
完整的代码:如下:
1usingSystem;
2usingSystem.Collections.Generic;
3usingSystem.Text;
4usingSystem.Web;
5usingSystem.Web.UI;
6usingSystem.Web.UI.WebControls;
7usingSystem.ComponentModel;
8
9namespaceLoginControl
10{
11 publicclassLogin:CompositeControl,IPostBackDataHandler
12 {
13 #region要组合的控件
14 LabellbUserName;
15 LabellbUserPassward;
16 TextBoxtxtUserName;
17 TextBoxtxtUserPassward;
18 ButtonsubmitButton;
19 #endregion
20
21
22 #region重写方法CreateChildControls
23
24 protectedoverridevoidCreateChildControls()
25 {
26 Controls.Clear();
27
28 //初始化控件lbUserName
29 lbUserName=newLabel();
30 lbUserName.Text="用户名:";
31 lbUserName.ID="lbUserName";
32 //把控件添加到我们的组合控件中
33 Controls.Add(lbUserName);
34
35 //初始化控件lbUserPassward
36 lbUserPassward=newLabel();
37 lbUserPassward.Text="密 码:";
38 lbUserPassward.ID="lbUserPassward";
39 Controls.Add(lbUserPassward);
40
41
42 txtUserName=newTextBox();
43 txtUserName.ID="txtUserName";
44 txtUserName.Width=Unit.Percentage(60);
45 Controls.Add(txtUserName);
46
47 txtUserPassward=newTextBox();
48 txtUserPassward.ID="txtUserPassward";
49 txtUserPassward.Width=Unit.Percentage(60);
50 Controls.Add(txtUserPassward);
51
52 submitButton =newButton();
53 submitButton.Text="提交";
54 submitButton.CommandName="Validate";
55 Controls.Add(submitButton);
56
57 ChildControlsCreated=true;
58 }
59 #endregion
60 #region将组合的子控件的属性呈现为组合控件的属性
61
62 publicstringUserNameLabelText
63 {
64 get
65 {
66 EnsureChildControls();
67 returnlbUserName.Text;
68 }
69 set
70 {
71 EnsureChildControls();
72 lbUserName.Text=value;
73 }
74 }
75
76 publicstringUserPasswardLabelText
77 {
78 get
79 {
80 EnsureChildControls();
81 returnlbUserPassward.Text;
82 }
83 set
84 {
85 EnsureChildControls();
86 lbUserPassward.Text=value;
87 }
88 }
89
90 publicstringSubmitButtonText
91 {
92 get
93 {
94 EnsureChildControls();
95 returnsubmitButton.Text;
96 }
97 set
98 {
99 EnsureChildControls();
100 submitButton=value;
101 }
102 }
103
104
105 #endregion
106
107 #region组合控件呈现的样式
108 protectedoverrideHtmlTextWriterTagTagKey
109 {
110 get
111 {
112 returnHtmlTextWriterTag.Table;
113 }
114 }
115
116 protectedoverridevoidRenderContents(HtmlTextWriterwriter)
117 {
118
119 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
120
121 writer.RenderBeginTag(HtmlTextWriterTag.Td);
122 lbUserName.RenderControl(writer);
123 writer.RenderEndTag();//td的结束
124
125 writer.RenderBeginTag(HtmlTextWriterTag.Td);
126 txtUserName.RenderControl(writer);
127 writer.RenderBeginTag();
128
129 writer.RenderBeginTag();//tr的结束
130
131 //***********************************************
132
133 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
134
135 writer.RenderBeginTag(HtmlTextWriterTag.Td);
136 lbUserPassward.RenderControl(writer);
137 writer.RenderEndTag();//td的结束
138
139 writer.RenderBeginTag(HtmlTextWriterTag.Td);
140 txtUserPassward.RenderControl(writer);
141 writer.RenderBeginTag();
142
143 writer.RenderBeginTag();//tr的结束
144
145 //***********************************************
146
147 writer.RenderBeginTag(HtmlTextWriterTag.Tr);
148
149 writer.AddAttribute(HtmlTextWriterAttribute.Colspan,"2");
150 writer.AddAttribute(HtmlTextWriterAttribute.Align,"center");
151 writer.RenderBeginTag(HtmlTextWriterTag.Td);
152 submitButton.RenderControl(writer);
153 writer.RenderBeginTag();
154
155 writer.RenderBeginTag();//tr的结束
156
157
158
159
160 }
161 #endregion
162
163
164
165 }
166}
167