2004-10-15+ 自定义控件 (呈现和处理回发)
推荐一个关于该方面知识的视频,是微软的网络讲座系列。如果对自定义控件不是很了解,可以看这个先 :)
---ASP.NET系列讲座三:Web 表单高级技巧----
控件在页面的呈现靠Render方法完成。该方法接收一个HtmlTextWriter类型的参数,用来向页面输出HTML标记。因为我们要编写自己的控件,首先要做的就是改写Render方法。下面是一个简单的控件,用来向页面输出一行文字。
public class Message : Control
{
#region 向页面输出HTML标记
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.Write("hello world !");
}
#endregion
}
用这个办法呈现html不是很好,实际上,HtmlTextWriter提供了三种呈现html的方法,其中推荐使用的就是基于堆栈的方法,诸如RenderBeginTag、AddAttribute、RenderEndTag等方法容易的构造嵌套的html元素块。(和XmlTextWriter差不多吧……)
#region 向页面输出HTML
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Width,"100%");
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Bgcolor,"#ff6633");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("hello world !");
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
#endregion
详细的信息可以查阅sdk文档。
下面重点说说回发的处理。主要是两类要求,一是控件本身处理由自己引发的回发事件,再一个是处理控件的回发数据。这两个分别有不同的接口予以支持。
为了说明这两个接口,看下面的控件,该控件由一个文本框和一个按钮组成,按钮用来提交控件自身。
public class Message : WebControl, IPostBackDataHandler,IPostBackEventHandler
{
private string msg;
//控件自己的事件,可以通过发送事件给外部调用者得到更丰富的处理手段
public event System.EventHandler Receive;
#region 属性
/// <summary>
/// 要显示的信息
/// </summary>
public string Msg
{
get{return this.msg;}
set{this.msg=value;}
}
#endregion
#region 向页面输出HTML
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Width,"100%");
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Bgcolor,"#ff6633");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("today's message is: {0}",msg);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("<input type=text name=\"{0}\" >",this.UniqueID);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("<input type=button onclick=\"{0}\" value=\"click me\">",Page.GetPostBackEventReference(this));
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
#endregion
#region IPostBackDataHandler 成员
//当由类实现时,用信号要求服务器控件对象通知 ASP.NET 应用程序该控件的状态已更改。
public void RaisePostDataChangedEvent()
{
//发送事件
if(this.Receive!=null)
Receive(this,new EventArgs());
}
//该方法先执行
//当由类实现时,为 ASP.NET 服务器控件处理回发数据。
public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
this.msg=postCollection[this.UniqueID];
return true;
}
#endregion
#region IPostBackEventHandler 成员
//该方法后执行
//向页面输出信息,确认该方法被调用
//当由类实现时,使服务器控件能够处理将窗体发送到服务器时引发的事件。
public void RaisePostBackEvent(string eventArgument)
{
Page.Response.Write("click !"+eventArgument.ToString());
}
#endregion
}
测试页面:有一个自定义控件,还有一个webcontrol的button控件,这个用于提交。
.aspx文件
<%@ Page language="c#" Codebehind="UseCC.aspx.cs" AutoEventWireup="false" Inherits="CustomControl.UseCC" trace=true%>
<%@ Register TagPrefix="cc1" Namespace="CC" Assembly="CC" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>UseCC</title>
<meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<FONT face="宋体">
<P>
<cc1:Message id="Message1" runat="server"></cc1:Message></P>
<P>
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button></P>
<P> </P>
</FONT>
</form>
</body>
</HTML>
.cs文件
public class UseCC : System.Web.UI.Page
{
protected CC.Message Message1;
protected System.Web.UI.WebControls.Button Button1;
private void Page_Load(object sender, System.EventArgs e)
{
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
//定阅message控件的事件
this.Message1.Receive += new System.EventHandler(this.Message1_Receive);
this.Button1.Click += new System.EventHandler(this.Button1_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
//处理Receive事件的方法
private void Message1_Receive(object sender, System.EventArgs e)
{
Response.Write("haha Received!!!");
}
private void Button1_Click(object sender, System.EventArgs e)
{
Response.Write("<br>=============="+Message1.Msg+"<br>");
}
}
要控件本身处理由自己引发的回发事件,需要控件实现IPostBackEventHandler接口,如果不需要在控件内部处理这样的回发,就不需要实现该接口。
#region IPostBackEventHandler 成员
//向页面输出信息,确认该方法被调用
//当由类实现时,使服务器控件能够处理将窗体发送到服务器时引发的事件。
public void RaisePostBackEvent(string eventArgument)
{
Page.Response.Write("click !");
}
#endregion
大家可以实验一下,如果你点message控件里面的button,就可以调用该方法,但是如果点外面的button,就不会调用该方法。
处理控件的回发数据,需要实现IPostBackDataHandler接口,通过实现接口的两个方法,来完成数据处理。在这里可以把响应的数据赋给控件的属性,这样就可以从外面使用数据。这里同时还准备了用来发送控件事件的方法。
#region IPostBackDataHandler 成员
//当由类实现时,用信号要求服务器控件对象通知 ASP.NET 应用程序该控件的状态已更改。
public void RaisePostDataChangedEvent()
{
//发送事件
if(this.Receive!=null)
Receive(this,new EventArgs());
}
//该方法先执行
//当由类实现时,为 ASP.NET 服务器控件处理回发数据。
//该方法如返回true,则接着调用RaisePostDataChangedEvent方法,false时,则不调用。
public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
//postCollection存放了回传的数据,通过使用索引来获得该控件的数据
//UniqueID是控件的唯一标识符
this.msg=postCollection[this.UniqueID];
return true;
}
#endregion