大家好,今天我们来实现一个自定义的控件,之前我们已经知道了,要开发自定义的控件一般继承三个基类:Control,WebControl,还有一个就是今天要说的CompositeControl。
大家也许还记得,之前的开发的控件基本上都是我们自己从头到尾的写一些控件的标记,如
之类的,而且还有一个大的问题:我们为了使得我们的控件更加的好用,专业,我们还实现了大量的接口,和自己写很多的事件.这样开发控件的时间就加大了。其实我们可以利用ASP.NET中已经有的控件,经过我们包装,实现我们自定义控件。大家可能认为这和用户控件差不多的,但是继承CompositeConytol的控件的自定义控件的灵活性和复用行更好,而且还还添加样式。
还一个更加重要的就是我们不必要实现接口,比如,引发回传的IPostBackEventHandler接口,接受数据的IPostBackDataHandler接口。大家还记得我们之前开发控件中的的那个Button还要申明name为 this.UniqueID ,现在我们都不需要了,因为我们要包装的那些服务器的控件,如TextBox,他们都已经实现了这些。
本章准备开发一个大家都熟知的Login登录控件。
大家先看看效果:
其实分析起来,这个控件是由一些已有的控件组合而成的,分别是:
两个Label,两个TextBox,和一个Button
下面我们就来开发:
首先,还是先继承CompositeControl;
- public class Login:CompositeControl
然后把就申明我们要组合的控件,如上所说的:
- //要组合的控件
- Label lbUserName;
- Label lbUserPassward;
- TextBox txtUserName;
- TextBox txtUserPassward;
把控件申明了之后只要初始化,并且将这些控件整合成我们的Login 控件就可以了。这么做呢?
其实开发组合控件很简单,一般只要重写一个方法就可以了。这个方法就是来初始化并且整合那些已经申明了的小控件的。如下:
- #region 重写方法CreateChildControls
-
- protected override void CreateChildControls()
- {
- //清空控件,大家可以理解为:初始化一张白纸,好让我们来画画
- Controls.Clear();
- //初始化控件lbUserName
- lbUserName = new Label();
- lbUserName.Text = "用户名:";
- lbUserName.ID = "lbUserName";
- //把控件添加到我们的组合控件中
- Controls.Add(lbUserName);
- //初始化控件lbUserPassward
- lbUserPassward = new Label();
- lbUserPassward.Text = "密 码:";
- lbUserPassward.ID = "lbUserPassward";
- Controls.Add(lbUserPassward);
- //初始化控件txtUserName
- txtUserName = new TextBox();
- txtUserName.ID = "txtUserName";
- txtUserName.Width = Unit.Percentage(60);
- Controls.Add(txtUserName);
-
- //初始化控件txtUserPassward
- txtUserPassward = new TextBox();
- txtUserPassward.ID = "txtUserPassward";
- txtUserPassward.Width = Unit.Percentage(60);
- Controls.Add(txtUserPassward);
- //初始化控件 submitButton
- submitButton = new Button();
- submitButton.Text = "提交";
- submitButton.CommandName = "Validate";
- Controls.Add(submitButton);
-
- 告诉编译器,控件已经初始化了
- ChildControlsCreated = true;
- }
- #endregion
大家特别要注意,最后的那句ChildControlsCreated属性,一定要申明,因为在页面的声明周期的任何时候可能调用上面的那个方法,如果不申明ChildControlsCreated,那么这个方法就会被反复的调用,那么我们控件的状态都会丢失。
如果申明了ChildControlsCreated=true,那么这个方法就调用一次。
经过上面的步骤之后,其实我们的控件就已经开发完成了。
可能我们还想进一步的向我们ASP.NET的标准的Login控件靠拢.那么我们的控件还缺少什么
属性,事件!!!
以前我们定义属性都是用的ViewState["..."],但是这里就不同了。因为我们的控件是有很多的小的控件组合起来的,比如,我们修改“用户名:”的那个Label,我们想改的是那个Label的属性,还是看看效果图:
改前的图: 改后的图
就是说,我们想把子控件的属性如Text,name等等,把这些属性上升呈现为组合控件Login的属性。
怎么做?
也很简单的:如下:
- public string UserNameLabelText
- {
- get
- {
- EnsureChildControls();
- return lbUserName.Text;
- }
- set
- {
- EnsureChildControls();
- lbUserName.Text = value;
- }
- }
这样我们就把那个显示用户名的Label的Text属性显示为了Login控件的UserNameLabelText属性。大家要注意 EnsureChildControls(); 这个方法的调用。其实是个保险的:确保我们要显示属性的那个控件已经创建,已经初始化了。
大家可以根据需要显示更加多的属性。也可以自己定义一些属性,还是像以前那样,可以用ViewState[''.."]
如果到这里为止,就差不多了。大家可以按按照上面的方法来写控件。
大家可以看见,控件的呈现很乱。那些Label.TextBox都布局的很乱。其实你可以根据需要来将上面的那些控件排列的更加好看些,只要重写一个方法就行了:
- protected override void RenderContents(HtmlTextWriter writer)
还是像之前一样,我们想把控件用一个Table来布局,先这样
- protected override HtmlTextWriterTag TagKey
- {
- get
- {
- return HtmlTextWriterTag.Table;
- }
- }
然后再把那些Label,TextBox,Button放到table的行和列中就行了。如下:
- protected override void RenderContents(HtmlTextWriter writer)
- {
- writer.RenderBeginTag(HtmlTextWriterTag.Tr);
- writer.RenderBeginTag(HtmlTextWriterTag.Td);
- lbUserName.RenderControl(writer);
- writer.RenderEndTag();//td的结束
- writer.RenderBeginTag(HtmlTextWriterTag.Td);
- txtUserName.RenderControl(writer);
- writer.RenderBeginTag();
- writer.RenderBeginTag();//tr的结束
- //***********************************************
- writer.RenderBeginTag(HtmlTextWriterTag.Tr);
- writer.RenderBeginTag(HtmlTextWriterTag.Td);
- lbUserPassward.RenderControl(writer);
- writer.RenderEndTag();//td的结束
- writer.RenderBeginTag(HtmlTextWriterTag.Td);
- txtUserPassward.RenderControl(writer);
- writer.RenderBeginTag();
- writer.RenderBeginTag();//tr的结束
- //***********************************************
- writer.RenderBeginTag(HtmlTextWriterTag.Tr);
- writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
- writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
- writer.RenderBeginTag(HtmlTextWriterTag.Td);
- submitButton.RenderControl(writer);
- writer.RenderBeginTag();
- writer.RenderBeginTag();//tr的结束
- }
这样,我们的控件就写完了。
我们的控件还差事件。我们在下篇将“事件的冒泡”。
完整的代码:如下: