复合控件
概念:
所谓复合控件:简单的理解就是将多个基本的控件组合成一个控件,从而实现自己想要的效果。微软为ASP.NET2.0中推出的登录控件等就是一个复合控件。从功能的实现上,复合式控件有点像用户控件,只是一个是.ascx文件,一个是.dll文件。
呈现简单的复合控件:
要想呈现一个复合控件,需要了解以下几个方面:
-->实现INamingContainer接口。
任何实现该接口的控件都创建一个新的命名空间,在这个新的命名空间中,所有子控件 ID 属性在整个应用程序内保证是唯一的。
-->Control.CreateChildControls 方法。
由 ASP.NET 页面框架调用,以通知使用基于合成的实现的服务器控件创建它们包含的任何子控件,以便为回发或呈现做准备。 当开发复合服务器控件或模板服务器控件时,必须重写此方法。重写 CreateChildControls 方法的控件应实现 INamingContainer 接口以避免命名冲突。
-->Control.ChildControlsCreated 属性。
获取一个值,该值指示是否已创建服务器控件的子控件。
-->Control.EnsureChildControls 方法。
确定服务器控件是否包含子控件。如果不包含,则创建子控件。
下面就通过实例来呈现个简单的复合登陆控件:创建ASP.NET服务器控件工程。complexControl。
先来看代码:
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:LoginControlrunat=serverButtonText='登录'NameLabel='用户名:'PasswordLabel='用户密码:'></{0}:LoginControl>")]
publicclassLoginControl:WebControl,INamingContainer,IPostBackEventHandler
{
privateButton_button;
privateTextBox_nameTextBox;
privateLabel_nameLabel;
privateTextBox_passwordTextBox;
privateLabel_passwordLabel;
privateRequiredFieldValidator_nameValidator;
privateRequiredFieldValidator_passwordValidator;
[Bindable(true),Category("Appearance"),DefaultValue(""),Description("按钮文本")]
publicstringButtonText
{
get
{
EnsureChildControls();//确定服务器控件是否包含子控件
return_button.Text;
}
set
{
EnsureChildControls();
_button.Text=value;
}
}
[Bindable(true),Category("Default"),DefaultValue(""),Description("姓名")]
publicstringName
{
get
{
EnsureChildControls();
return_nameTextBox.Text;
}
set
{
EnsureChildControls();
_nameTextBox.Text=value;
}
}
[Bindable(true),Category("Appearance"),DefaultValue(""),Description("必须输入姓名")]
publicstringNameErrorMessage
{
get
{
EnsureChildControls();
return_nameValidator.ErrorMessage;
}
set
{
EnsureChildControls();
_nameValidator.ErrorMessage=value;
_nameValidator.ToolTip=value;
}
}
[Bindable(true),Category("Apperance"),DefaultValue(""),Description("姓名标签")]
publicstringNameLabel
{
get
{
EnsureChildControls();
return_nameLabel.Text;
}
set
{
EnsureChildControls();
_nameLabel.Text=value;
}
}
[Browsable(false),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
publicstringPassword
{
get
{
EnsureChildControls();
return_passwordTextBox.Text;
}
}
[Bindable(true),Category("Appearance"),DefaultValue(""),Description("必须输入密码")]
publicstringPasswordErrorMessage
{
get
{
EnsureChildControls();
return_passwordValidator.ErrorMessage;
}
set
{
EnsureChildControls();
_passwordValidator.ErrorMessage=value;
_passwordValidator.ToolTip=value;
}
}
[Bindable(true),Category("Appearance"),DefaultValue(""),Description("密码标签")]
publicstringPasswordLabel
{
get
{
EnsureChildControls();
return_passwordLabel.Text;
}
set
{
EnsureChildControls();
_passwordLabel.Text=value;
}
}
protectedoverridevoidCreateChildControls()
{
Controls.Clear();
_nameLabel=newLabel();
_nameTextBox=newTextBox();
_nameTextBox.ID="nameTextBox";
_nameValidator=newRequiredFieldValidator();
_nameValidator.ID="validator1";
_nameValidator.ControlToValidate=_nameTextBox.ID;
_nameValidator.Text="*";
_nameValidator.Display=ValidatorDisplay.Static;
_passwordLabel=newLabel();
_passwordTextBox=newTextBox();
_passwordTextBox.TextMode=TextBoxMode.Password;
_passwordTextBox.ID="passwordTextBox";
_passwordValidator=newRequiredFieldValidator();
_passwordValidator.ID="validator2";
_passwordValidator.ControlToValidate=_passwordTextBox.ID;
_passwordValidator.Text="*";
_passwordValidator.Display=ValidatorDisplay.Static;
_button=newButton();
_button.ID="button1";
//_button.Click+=newEventHandler(_button_Click);
_button.CommandName="ClickLogin";
this.Controls.Add(_nameLabel);
this.Controls.Add(_nameTextBox);
this.Controls.Add(_nameValidator);
this.Controls.Add(_passwordLabel);
this.Controls.Add(_passwordTextBox);
this.Controls.Add(_passwordValidator);
this.Controls.Add(_button);
}
protectedoverridevoidRender(HtmlTextWriterwriter)
{
AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding,
"1",false);
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_nameLabel.RenderControl(writer);
writer.RenderEndTag();//Td
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_nameTextBox.RenderControl(writer);
writer.RenderEndTag();//Td
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_nameValidator.RenderControl(writer);
writer.RenderEndTag();//Td
writer.RenderEndTag();//Tr
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_passwordLabel.RenderControl(writer);
writer.RenderEndTag();//Td
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_passwordTextBox.RenderControl(writer);
writer.RenderEndTag();//Td
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_passwordValidator.RenderControl(writer);
writer.RenderEndTag();//Td
writer.RenderEndTag();//Tr
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Colspan,"2");
writer.AddAttribute(HtmlTextWriterAttribute.Align,"right");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_button.RenderControl(writer);
//writer.AddAttribute(HtmlTextWriterAttribute,Page.GetPostBackEventReference(_button));
writer.RenderEndTag();//Td
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(" ");
writer.RenderEndTag();//Td
writer.RenderEndTag();//Tr
writer.RenderEndTag();//Table
}
}
}
首先我们实例化了几个现有控件的对象。然后声明了一大堆的属性,要注意的:和平时定义属性不同,我们在每一个属性中都添加了EnsureChildControls ()方法。其他的没有任何变化,和一般的属性声明一样。
接下来我们从写了重要的CreateChildControls()。将前面声明好的实例化控件对象添加到controlcollection中。融合成一个控件。
最后重写控件显示的Render()方法。生成登录窗体的样式。效果如下:
这样,我们基本上就完成了复合控件的基本显示功能。
复合控件的事件处理:
由于复合控件中包含子控件,这就使得复合控件的事件处理变得复杂起来。由于不允许开发人员直接访问子控件,如果子控件的事件不能作为顶级事件引发,那么将无法实现子控件的事件处理。
我们可以以两种形式来完成事件的处理:一是直接将事件封装到控件中,显然灵活性很差。二就是自定义事件,用户来完成事件的代码。
第一种情况比较简单:就是在创建我们得控件时,将要实现的效果直接封装在dll中。这里就不做说明了。
但是往往控件触发时,我们想做自己的事情,这就是第二种情况的事件处理。这就需要把事件交给主控件,由主控件统一暴露事件,这样开发人员在使用控件时仅需要为主控件注册事件即可,剩下的由主控件负责引发子控件的事件或执行子控件的某些功能,这里就涉及主控件与其子控件的事件衔接问题,复合控件的这种事件处理,主要是实现子控件事件上传的过程。一般分为:包含法和冒泡法两种处理方式。
-->包含法:
基本思想是:通过在子控件的事件处理程序中调用复合控件的顶层事件处理程序,以完成子控件的事件上传。在CreateChildControls方法中,为子控件添加事件处理程序。
接着上面登陆控件的例子,来实现下登录按钮的事件。
首先在CreateChildControls()中,为_button添加单击事件。(其他代码略)
_button.ID = " button1 " ;
_button.Click += new EventHandler(_button_Click);
然后创建主控件对外的处理函数:
{
OnClickLogin(EventArgs.Empty);
}
private static readonly object EventClickLogin = new object ();
public event EventHandlerClickLogin
{
add
{
Events.AddHandler(EventClickLogin,value);
}
remove
{
Events.RemoveHandler(EventClickLogin,value);