前言:
前面讲到了复合控件的视图,今天将进入其复合控件的事件机制世界
本节将讲述:
- 为什么要事件冒泡(事件上传)
- 什么是复合控件事件冒泡(事件上传)
- 复合控件事件的实现原理
- 实现事件冒泡(事件上传)的步骤。
正文:
(一)为什么要事件上传
复合控件中包含子控件,这就使得复合控件的事件处理变得复杂起来。显而易见,在复合控件的事件实现过程中,需要面临的最大问题是:由于不允许开发人员直接访问子控件(虽然通过Controls集合访问的方法可以实现,但是破坏了程序的封装性,因此是不被允许的),如果子控件的事件不能作为顶级事件引发,那么将无法实现子控件的事件处理。简单的说,即如何实现子控件的事件上传。所谓事件上传是指把子控件的事件暴露为顶级事件,这样父控件可以检查到事件,并按照定义来执行相关事件处理程序.
(二) 什么是复合控件事件冒泡(事件上传)
其核心是使用ASP.NET 2.0框架提供的事件上传机制。这种机制允许子控件将事件沿其包容层次结构向上传播到合适的位置引发,并且允许将事件处理程序附加到原始控件以及公开冒泡的事件的控件上
(三)复合控件的实现原理
页面框架提供了一个事件上传架构,通过它控件可能把某个事件上传(bubble)到控件层次,一个上传事件可能在引发它时或其他时候来处理,更方便的处理时机是在控件树的高层,复合控件可能用这个特征把子控件上传的事件暴露为顶层事件。例如:DataList控件把包含在ItemTemplate 中的Button控件的Command事件暴露为顶层的ItemCommand事件。而command事件(
它的事件数据类派生自CommandEventArgs)由asp.net的内建控件上传的惟一事件,也可以实现初始化上传的其他事件。
事件上传由OnBubbleEvent 和RaiseBubbleEvent方法来启动的,这些方法在Control类中的定义如下:
//定义复合控件的事件是否沿页面的UI 服务器控件层次结构向上传递。
//如果子控件的事件向上传递,则为true;否则为false。默认值为false
protected virtual bool OnBubbleEvent(object source,EventArgs args)
{
return false;
}
(四) 实现事件冒泡(事件上传)的步骤。
只要在自定义控件中,重写OnBubbleEvent方法,就能实现事件冒泡。因为在其子控件内部有一个OnCommand方法,它调用了RaiseBubbleEvent方法。而RaiseBubbleEvent调用了OnBubbleEvent方法。
示例:
protected override bool OnBubbleEvent(object sender,EventArgs e){
bool handled = false;
if(e is CommandEventArgs) {
CommandEventArgs ce = (CommandEventArgs)e;
if(ce.CommandName == "ButtonClick") {
OnButtonClick(EventArgs.Empty);
handled =true;
}
}
return handled;
}
本节用到的示例控件代码:
示例代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.ComponentModel.Design;
using System.ComponentModel;
/**//// <summary>
/// Class2 的摘要说明
/// </summary>
///
namespace Cnblogs.Sui
{
[DefaultEvent("Logon"),DefaultProperty("Name")]
public class Class2 : WebControl,INamingContainer
{
private Button _button;
private TextBox _nameTextBox;
private Label _nameLabel;
private Label _passwordLabel;
private TextBox _passwordText;
private RequiredFieldValidator _nameValidator;
private RequiredFieldValidator _passwordValidtor;
private static readonly object EventLogon=new object();
override properties#region override properties
public override ControlCollection Controls
{
get {
EnsureChildControls();
return base.Controls;
}
}
#endregion override properties
prorerties list#region prorerties list
[Bindable(true),Category("Appearance"),DefaultValue(""),Description("The text to display on the button")]
public string ButtonText
{
get{
EnsureChildControls();
return _button.Text;
}
set{
EnsureChildControls();
_button.Text=value;
}
}
[Bindable(true),Category("default"),DefaultValue(""),Description("the user name")]
public string Name{
get{
EnsureChildControls();
return _nameTextBox.Text;
}
set{
EnsureChildControls();
_nameTextBox.Text=value;
}
}
[Bindable(true),Category("Apearance"),DefaultValue(""),Description("Error Message of the validator used for the Name")]
public string NameErrorMessage{
get{
EnsureChildControls();
return _nameValidator.ErrorMessage;
}
set{
EnsureChildControls();
_nameValidator.ErrorMessage=value;
_nameValidator.ToolTip=value;
}
}
[Bindable(true),Category("Apperance"),DefaultValue(""),Description("the text for the name Label")]
public string NameLabel
{
get{
EnsureChildControls();
return _nameLabel.Text;
}
set{
EnsureChildControls();
_nameLabel.Text=value;
}
}
[Bindable(true),DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string Password
{
get{
EnsureChildControls();
return _passwordText.Text;
}
}
[Bindable(true),Category("Appearance"),DefaultValue(""),Description("Error Message of the validator used for the Password")]
public string PasswordErrorMessage
{
get{
EnsureChildControls();
return _passwordValidtor.ErrorMessage;
}
set{
EnsureChildControls();
_passwordValidtor.ErrorMessage=value;
_passwordValidtor.ToolTip=value;
}
}
[Bindable(true),Category("Appearance"),DefaultValue(""),Description("the text for the password label")]
public string PasswordLabel
{
get{
EnsureChildControls();
return _passwordLabel.Text;
}
set{
EnsureChildControls();
_passwordLabel.Text=value;
}
}
#endregion
events#region events
[Category("Action"),Description("Raised when the user chicks the login button")]
public event EventHandler Logon
{
add{
Events.AddHandler(EventLogon,value);
}
remove{
Events.RemoveHandler(EventLogon,value);
}
}
public virtual void OnLogon(EventArgs e){
EventHandler logonHandler=(EventHandler)Events[EventLogon];
if(logonHandler !=null)
{
logonHandler(this,e);
}
}
#endregion
Event bubbling#region Event bubbling
//the use of event bubbling in this seenario is somewhat contrived;
//we have implemented it mainly for demostration purposes
//in this case you could instead
//raise the Logon event from an event handler wired to the
//click event or to the command event of the button control
protected override bool OnBubbleEvent(object source, EventArgs e)
{
bool handled=false;
if(e is CommandEventArgs)
{
CommandEventArgs ce=(CommandEventArgs)e;
if(ce.CommandName=="Logon")
{
OnLogon(EventArgs.Empty);
handled=true;
}
}
return handled;
}
#endregion
override methods#region override methods
protected override void CreateChildControls()
{
Controls.Clear();
_nameLabel=new Label();
_nameTextBox=new TextBox();
_nameTextBox.ID="nameTextBox";
_nameValidator=new RequiredFieldValidator();
_nameValidator.ID="validator1";
_nameValidator.ControlToValidate=_nameTextBox.ID;
_nameValidator.Text="*";
_nameValidator.Display=ValidatorDisplay.Static;
_passwordLabel=new Label();
_passwordText=new TextBox();
_passwordText.TextMode=TextBoxMode.Password;
_passwordText.ID="passwordTextBox";
_passwordValidtor=new RequiredFieldValidator();
_passwordValidtor.ID="validator2";
_passwordValidtor.ControlToValidate=_passwordText.ID;
_passwordValidtor.Text="*";
_passwordValidtor.Display=ValidatorDisplay.Static;
_button=new Button();
_button.ID="button1";
_button.CommandName="Logon";
this.Controls.Add(_nameLabel);
this.Controls.Add(_nameTextBox);
this.Controls.Add(_nameValidator);
this.Controls.Add(_passwordLabel);
this.Controls.Add(_passwordText);
this.Controls.Add(_passwordValidtor);
this.Controls.Add(_button);
base.CreateChildControls();
}
#endregion
protected override void Render(HtmlTextWriter writer)
{
AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding,"1",false);
writer.AddAttribute(HtmlTextWriterAttribute.Border, "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);
_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);
_passwordText.RenderControl(writer);
_passwordValidtor.RenderControl(writer);
writer.RenderEndTag();//TD
writer.RenderEndTag();//tr
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Colspan,"2");
writer.AddAttribute(HtmlTextWriterAttribute.Align,"center");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
_button.RenderControl(writer);
writer.RenderEndTag();//td
writer.RenderBeginTag(HtmlTextWriterTag.Td);
// writer.Write(" ");
writer.RenderEndTag();//td
writer.RenderEndTag();//tr
writer.RenderEndTag();//Table
// base.Render(writer);
}
public Class2()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
}
}