3.4
控件开发相关的接口介绍
3.4.1 IPostBackDataHandler接口
我们对表单通常的做法是回送给它本身,因此我们需要一种机制来比较当前值和在当前请求中发送给客户端的值。
实现IPostBackDataHandler接口的控件就可以得到这一机制,实现这一接口的控件可以检查提交给页面的数据
并检查数据是否在客户端被修改过。IPostBackDataHandler接口下定义了2个方法:
public interface IPostBackDataHandler
{
bool LoadPostData(string postDataKey, NameValueCollection postCollection);
void RaisePostDataChangedEvent();
}
当LoadPostData方法在控件上实现的时候可被Framework调用来检查提交给页面的数据。第二个参数是提交给
页面的值的集合,第一个参数是个关键值,为当前控件识别数据。因为当我们要访问集合中的控件数据时可以用下面的
方法:
string text1=postCollection[postDataKey];
在这个方法中我们可以检查发送的数据值并与已经提交给客户端的数据值进行比较。当数据被修改我们就返回true,
如果没被修改我们就返回false,当该方法的返回值为true时那么这个接口的另一个被实现的
方法RaisePostDataChangedEvent会被Framework调用,这样我们就可以根据数据的变化引发事件。一般我们在该方
法中调用OnEvent方法来引发事件。下面我们举个例子来看看如何使用该接口(例3-7),该例子的源代码大家可以下载。
例3-7:
省略……
using
System.Collections.Specialized; //参数NameValueCollection类型要用到
namespace
interface_postdata_3_7
{
///<summary>
/// WebCustomControl1 的摘要说明。
///</summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]
//继承接口IPostBackDataHandler
public class WebCustomControl1 : WebControl,IPostBackDataHandler
{
public event EventHandler TextChanged; //定义一个事件
public WebCustomControl1():base(HtmlTextWriterTag.Input)
{
}
public string Text //定义一个属性保存值
{
get
{
if(this.ViewState["text"]!=null)
{
return this.ViewState["text"].ToString();
}
return string.Empty;
}
set
{
this.ViewState["text"] = value;
}
}
//实现接口的LoadPostData方法
bool IPostBackDataHandler.LoadPostData(string postDataKey,NameValueCollection postCollection)
{
string text1 = this.Text; //得到当前数据值
string text2 = postCollection[postDataKey]; //得到提交的数据值
if (!text1.Equals(text2)) //比较当前数据值与页面提交的数据值
{
this.Text = text2; //如果数据改变就保存数据
return true; //返回true保证RaisePostDataChangedEvent被调用
}
return false;
}
//实现接口的RaisePostDataChangedEvent方法
void IPostBackDataHandler.RaisePostDataChangedEvent()
{
this.OnTextChanged(EventArgs.Empty); //调用事件的触发方法
}
//触发事件
protected virtual void OnTextChanged(EventArgs e)
{
if(TextChanged!=null) //当事件不为空时触发事件
TextChanged(this,e);
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Name,this.UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Type,"text");
if(this.Text!=null)
{
writer.AddAttribute(HtmlTextWriterAttribute.Value,this.Text);
}
base.AddAttributesToRender (writer);
}
}
}
该控件实现了IPostBackDataHandler接口,用来比较值的改变,当值被改变时如果我们添加TextChanged事
件的处理函数那么该事件就会被触发。下面我们在来看下如何使用该控件。
首先我们必须将该控件添加到页面,那是每个控件的使用都必须的,接着我们修改后置代码(.cs文件)页面类如下:
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.TextBox TextBox1;
protected System.Web.UI.WebControls.Button Button1;
protected interface_postdata_3_7.WebCustomControl1 WebCustomControl11;
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
this.WebCustomControl11.TextChanged += new System.EventHandler(this.WebCustomControl11_TextChanged); //为事件添加处理函数
}
private void WebCustomControl11_TextChanged(object sender, System.EventArgs e)
{
TextBox1.Text=WebCustomControl11.Text; //改变TextBox控件的属性值
}
}
这里我们为程序添加了另外2个服务器控件Button和TextBox控件,当我们改变自定义服务器控件值时会调用事件
TextChanged的处理函数WebCustomControl11_TextChanged在该函数中我们改变了TextBox控件的属性值。下面我们
来看下显示结果(图3-10)
图3-10
当我们修改自定义控件文本框内容并单击Button按扭时显示结果如图(图3-11)
图3-11
这时TextBox控件文本框的内容页也变了,这是因为当我们修改自定义服务器控件属性时触发了TextChanged事件,在该
事件的处理函数中我们修改了TextBox控件控件的属性。
3.4.2 IPostBackEventHandler接口
该接口也是一个也于回送有关的重要接口,在该接口下定义了一个方法如下:
public interface IPostBackEventHandler
{
void RaisePostBackEvent(string eventArgument);
}
当我们编写带按扭的控件时,我们可能希望当我们单击按扭时可以触发一个事件,那么我们就可以通过实现该接口
来实现这一功能,因为RaisePostBackEvent方法可被启动回送的那个控件调用来获取回送的事件。在我们使用该接口
的时候可能还会调用Page类的一个方法,GetPostBackClientEvent方法,在客户端创建__doPostBack函数,从而使
用该函数来启动回送,这个方法有2个参数,第一个一般是启动回送的控件本身,第二个参数是一个string类型的参数,
可在回送中传递给RaisePostBackEvent方法,通过RaisePostBackEvent方法的参数我们可以得到该参数,一般我们
会通过传递的参数不同触发不同的事件。这个方法在这里讲讲大家似乎很难理解,我们还是用实例来说明,在该实例中我
们会定义两个按扭,分别触发两个不同的事件Post和Reset,下面我们还是来看看代码(例3-8)
例3-8:
using
System;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.ComponentModel;
namespace
interface_postevent_3_8
{
[DefaultProperty("Text"),
ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]
public class WebCustomControl1 : WebControl,IPostBackEventHandler
{
public event EventHandler Post; //定义2个事件
public event EventHandler Reset;
//实现IPostBackEventHandler
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
if(eventArgument=="post") //根据传递的参数调用不同函数触发不同的事件
{
OnPost(EventArgs.Empty);
}
if(eventArgument=="reset")
{
OnReset(EventArgs.Empty);
}
}
private void OnPost(EventArgs e) //触发事件函数
{
if(Post!=null)
Post(this,e);
}
private void OnReset(EventArgs e)
{
if(Reset!=null)
Reset(this,e);
}
//为页面添加两个按扭
protected override void Render(HtmlTextWriter writer)
{
//不能把2个按扭的名字设成一样的
writer.AddAttribute(HtmlTextWriterAttribute.Name,this.UniqueID+":post");
//在这里什么使用了Page的GetPostBackEventReference方法
writer.AddAttribute(HtmlTextWriterAttribute.Onclick,this.Page.GetPostBackEventReference(this,"post"));
writer.RenderBeginTag(HtmlTextWriterTag.Button);
writer.Write("Post");
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Name,this.UniqueID+":reset");
writer.AddAttribute(HtmlTextWriterAttribute.Onclick,this.Page.GetPostBackClientEvent(this,"reset"));
writer.RenderBeginTag(HtmlTextWriterTag.Button);
writer.Write("Reset");
writer.RenderEndTag();
base.RenderChildren(writer);
}
}
}
这是一个典型的实现IPostBackEventHandler接口的控件。它的使用方法如下:
public class WebForm1 : System.Web.UI.Page
{
protected interface_postevent_3_8.WebCustomControl1 WebCustomControl11;
protected System.Web.UI.WebControls.TextBox TextBox1;
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
WebCustomControl11.Post+=new EventHandler(WebCustomControl11_Post);
WebCustomControl11.Reset+=new EventHandler(WebCustomControl11_Reset);
}
private void WebCustomControl11_Post(object sender, System.EventArgs e)
{
TextBox1.Text="PostEvent";
}
private void WebCustomControl11_Reset(object sender, System.EventArgs e)
{
TextBox1.Text="Reset";
}
}
这里我们不写出所有的使用代码了,大家有兴趣可以下载源代码来运行下,在使用该控件我们,我们还添加一个TextBox控
件,根据单击的按扭不同触发不同的事件,在事件的处理函数中修改TextBox控件的Text属性为不同的值。同样我们来看
下显示结果(图3-12)
图3-12
当我们单击Post按扭,显示如图(图3-13)
图3-13
因为我们单击了Post按扭所以触发了Post事件,所以它的处理函数改变了文本框控件的内容为Post。下面我们单击Reset
按扭显示如图(图3-14)
图3-14
因为Reset事件的处理函数改变文本框的内容为Reset,所以显示就如图了啊。经对分析这个实现IPostBackEventHandler
接口的典型控件大家应该对数据和事件回送有了进一步的认识了吧。
3.4.3 INamingContainer接口
该接口没有任何的方法,是一个标记接口,但是该接口有一个实用的功能,实现了该接口的控件可以为它的子控件生成
一个不会与其他控件冲突的ID,例如我们有一个ID为myControl的控件,但是,在一个实现了该接口且ID为myContainer的
控件中包含一个相同控件,那么这个被包含控件的唯一ID会变成myContainer:myControl,这样就可以避免ID的冲突。该
接口还有一个重要的用途,实现了该接口的控件可以被子控件通过NamingContainer属性得到。
与控件编写相关的几个类与接口我们就先介绍到这里,当然这不是全部的,还有很多我们就不一一介绍了。我们在后面
几节中还会涉及到几个与控件编写相关的类或接口,比如:
ITemplate接口,我们会在介绍模版控件开发时使用到。