前一阵子,firelong说,应该用接口实现事件,而不应该用委托。我就希望他能给出一个用接口实现事件的方法,我是一直等呀,等到了现在也没有看到。
昨天又看到了,Snake@Net 说不要把接口和委托给混淆了的文章。也许我就把他们给混淆了吧。他的文章没仔细看,不过我倒是突然想到了一个用接口实现事件的方法,写了一个简单的demo测试了一下,居然还成功了。
所以拿出来抖落抖落。
这个只是体现了一个简单的思路,我并不想用他来证明什么,只是写着玩的。
==========================
建立两个项目,一个是web项目,一个是自定义服务器控件的项目。
服务器控件的项目里定义一个控件(EventTest)和一个接口(IEvent)。
代码如下
{
/// <summary>
/// 定义一个接口
/// </summary>
public interface IEvent
{
string MyName
{
get ;
set ;
}
string Test
{
get ;
set ;
}
void Event(System.Web.UI.Page page);
}
}
{
[DefaultProperty( " Text " )]
[ToolboxData( " <{0}:EventTest runat=server></{0}:EventTest> " )]
public class EventTest : WebControl, INamingContainer
{
TextBox txt = new TextBox();
HtmlInputButton btn = new HtmlInputButton();
private List < IEvent > _EventList = new List < IEvent > () ;
public List < IEvent > EventList
{
get { return _EventList; }
set { _EventList = value; }
}
protected override void CreateChildControls()
{
base .CreateChildControls();
// 创建一个文本框
txt.ID = " Txt_Test " ;
this .Controls.Add(txt);
// 创建一个HTML的按钮
btn.ID = " Btn_Test " ;
btn.Name = " event " ;
btn.Value = " 点击我 " ;
// 添加一个前台js事件
btn.Attributes.Add( " onclick " , " test(this) " );
this .Controls.Add(btn);
if ( base .Page.IsPostBack)
{
// 处理事件
if (_EventList != null )
{
// 有外部申请的事件
foreach (IEvent myEvent in _EventList)
{
base .Page.Response.Write( " ================<BR>控件内部事件——开始<BR> " );
base .Page.Response.Write(myEvent.MyName + " <BR> " );
myEvent.Test = base .Page.Request.Form[ " EventTest1$Txt_Test " ]; // DateTime.Today.ToString();
// 调用外部事件
myEvent.Event( base .Page);
base .Page.Response.Write( " 控件内部事件——结束<BR><BR><BR> " );
}
}
}
}
#region 设计时支持
/// <summary>
/// 设计时支持
/// </summary>
/// <param name="output"></param>
protected override void Render(HtmlTextWriter output)
{
if (( base .Site != null ) && base .Site.DesignMode)
{
output.Write( " <div style='TEXT-ALIGN: center;width:100%'> 用接口实现事件的测试</div> " );
}
else
{
// Page_Click();
base .Render(output);
}
}
#endregion
}
}
在web项目里的Default.aspx里面把自定义控件拖拽过来,在加点js脚本。Default.aspx.cs里在写几行代码。最重要的是定义一个类(MyEvent1),实现一下接口IEvent。
<% @ Register assembly = " MyEvent " namespace = " Nature.MyEvent " tagprefix = " cc1 " %>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title ></ title >
< script language ="javascript" >
function test(me)
{
alert( " 您单击了这个按钮,并且触发了一个事件,其实是表单提交。\n按确定后提交表单 " );
__doPostBack(me.id, "" );
}
</ script >
</ head >
< body >
< form id ="form1" runat ="server" >
< input type ="hidden" name ="__myEVENTTARGET" id ="__myEVENTTARGET" value ="" />
< input type ="hidden" name ="__myEVENTARGUMENT" id ="__myEVENTARGUMENT" value ="" />
< script type ="text/javascript" >
// <![CDATA[
var theForm = document.forms[ ' form1 ' ];
if ( ! theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if ( ! theForm.onsubmit || (theForm.onsubmit() != false )) {
theForm.__myEVENTTARGET.value = eventTarget;
theForm.__myEVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
// ]]>
</ script >
< div >
< cc1:EventTest ID ="EventTest1" runat ="server" />
</ div >
</ form >
</ body >
</ html >
{
public partial class _Default : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base .OnInit(e);
MyEvent1 e1 = new MyEvent1();
e1.MyName = " 第一个事件 " ;
MyEvent1 e2 = new MyEvent1();
e2.MyName = " 第二个事件 " ;
this .EventTest1.EventList.Add(e1);
this .EventTest1.EventList.Add(e2);
}
protected void Page_Load( object sender, EventArgs e)
{
}
}
public class MyEvent1 : Nature.MyEvent.IEvent
{
private string _MyName = "" ;
public string MyName
{
get { return _MyName;}
set { _MyName = value; }
}
private string _MyTest = "" ;
public string Test
{
get { return _MyTest; }
set { _MyTest = value; }
}
public void Event(System.Web.UI.Page page)
{
// 处理自己的事件
string str = " <BR>MyName:{0};<BR>MyTest:{1}<BR> " ;
page.Response.Write( " <BR>外部事件——开始<BR> " );
page.Response.Write( string .Format(str, this ._MyName, this ._MyTest));
page.Response.Write( " 外部事件——结束<BR><BR> " );
}
}
}
=================================
就是在自定义控件内部定义一个List,保存外部申请的接口,Default.aspx.cs往控件里加“接口”就可以了。然后是调用的问题。
调用的部分比较简单,直接在CreateChildControls()里面就调用了。
实现了几个功能:
1、在控件内部调用了外部的方法。
2、外部设置的属性可以传递到控件内部。
3、控件内部设置的属性也可以传递给外部。
4、可以获取表单值。
这里有一个很明显的缺点,每一种事件的处理方法,都要去定义一个类,并且实现一个接口,这个显然很麻烦。
================================
这是一个简单的思路,我不想用他证明用接口实现事件是更好的方法,也不想用他证明某个观点是正确的或者某个观点是错误的,更不想说微软的对与事件的解决方式有问题。
只是实现同一个目的(事件)的另一种方法。
这种方法还有很多问题,比如如何解决按钮和接口的对应问题?(这里就是一个按钮,一个接口,表单提交就是调用了,没有做是否对应的判断)
还有事件冒泡,还有效率、稳定性、可读性、用着是不是方便等问题。
这个只是玩一玩,所以请大家不要较真,呵呵。
最后,如果感兴趣的话,可以点 接口实现事件.rar 下载。
================================
顺便问个问题,我以前上传的文件和图片怎么都看不到了?