给自定义控件(Web Control)添加事件的几种方法。前两种方法可以不实现IPostBackEventHandler

简介:     写自定义控件已经好久了,也有几个用得时间比较长的,但是对于“事件”一直是比较模糊,没有很详细的理解。          最近升级分页控件,由于原来使用的是VB.net(在VB.net里面添加一个事件是比较容易的),现在想改用C#,而原来的方法又写得比较笨拙,想换一个更简洁一点的方法,所以不得不重新认识一下事件。

    写自定义控件已经好久了,也有几个用得时间比较长的,但是对于“事件”一直是比较模糊,没有很详细的理解。
    
    最近升级分页控件,由于原来使用的是VB.net(在VB.net里面添加一个事件是比较容易的),现在想改用C#,而原来的方法又写得比较笨拙,想换一个更简洁一点的方法,所以不得不重新认识一下事件。看了几遍《道不远人深入解析asp.net2.0控件开发》居然没有看懂,可能是自己太笨了吧。又找到了 自定义分页控件开发 看了几遍,还是比较迷糊,最后把《自定义分页控件开发》 里提供的代码down下来看了一下,终于有点明白了。

    先举一个简单的例子吧,我们建立一个复合控件,在CreateChildControls()里面添加两个控件,一个是Label,一个是LinkButton。我们的目的是要给自定义控件加一个事件,以便可以控制Label的Text属性。

     1、内部事件。
    这个好像是我起的名称,就是只在自定义控件的内部相应的事件,使用控件的页面不用相应相关的事件。具体一点就是要在自定义控件内部,在单击LinkButton的时候修改Label的值。   
public   class  EventTest : WebControl, INamingContainer  
    
{
protected override void CreateChildControls()
        
{
            Label lbl 
= new Label();
            lbl.ID 
= "lbl";
            
this.Controls.Add(lbl);
            
this.Controls.Add(new LiteralControl("<BR>"));
            LinkButton btn 
= new LinkButton();
            btn.ID 
= "btn";
            btn.Text 
= "复合控件的事件测试";
            
this.Controls.Add(btn);
 }

}



    编写好这段代码,然后把控件拖拽到页面里面里进行测试,运行后点击LinkButton,我们可以看到页面已经提交了,但是什么变化也没有,恩,我们还没有些事件呢。现在我们就给LinkButton加一个Click的事件。
protected   override   void  CreateChildControls()
        
{
            Label lbl 
= new Label();
            lbl.ID 
= "lbl"

            
this.Controls.Add(lbl);
            
this.Controls.Add(new LiteralControl("<BR>"));

            LinkButton btn 
= new LinkButton();
            btn.ID 
= "btn";
            btn.Text 
= "复合控件的事件测试";
            
this.Controls.Add(btn);

            
//给按钮添加内部事件            
            btn.Click += new EventHandler(btn_Click);
}


 
void  btn_Click( object  sender, EventArgs e)
        
{
            Label lbl 
= (Label)this.FindControl("lbl");
            lbl.Text 
+= "控件内部的事件,hi";
        }


    再次运行网页,单击,我们看到了想要的效果。

    怎么样简单吧,但是这种方法很不灵活,如果调用控件的网页也想相应事件怎么办呢?

     2、外部事件。
    这回我们要让自定义控件的外部也能相应事件。这个理论上我们要使用委托,也就是delegate,但是系统已经为我们定义好了一个( EventHandler),我们先用现成的。

    这样我们就给自定义控件定义了一个事件,重新编译,我们可以在控件的属性里面看到这个事件。(如果您没有看到,说明没有刷新,可能需要把IDE关闭,再次打开)。
 
public   event  EventHandler myClick
        
{
            add 
{
                Events.AddHandler(
this, value);
            }

            remove 
{
                Events.RemoveHandler(
this, value);
            }

        }


    我们可以添加外部的响应事件了,双击,我们加上几行代码。
在使用控件的网页里填写的代码  
protected   void  EventTest1_myClick( object  sender, EventArgs e)
        
{
            Label lbl 
= (Label)EventTest1.FindControl("lbl");
            lbl.Text 
+= "外部的事件,Hello" ;

        }



    运行,奇怪还是原来的样子,外部事件并没有相应,不是加了一个事件吗?外面的事件怎么没有被调用呢?这是因为,事件先触发自定义控件内部的事件,然后再由控件内部发出“命令”,调用外部的事件,那么我们怎样才能发出这个命令呢?我们需要要添加这个函数。这个也是最让我费解的地方,可能是对委托不是很了解的原因吧。
 
protected   void  TestClick( object  sender,EventArgs e)
        
{
            EventHandler hd 
= (EventHandler)base.Events[this];
            
if (hd != null)
            
{
                hd(sender, e);
            }

        }


    在修改一下  btn_Click() 就可以了。
void  btn_Click( object  sender, EventArgs e)
        
{
            Label lbl 
= (Label)this.FindControl("lbl");
            lbl.Text 
+= "控件内部的事件,hi";

            
//调用外部事件
            TestClick(sender, e);
        }

    再次运行,OK。

     (实现了内部和外部的事件相应,但是这时候我们还没有实现传说中的接口,这是为什么呢?)

    3、“借用”事件,没有成功。

    我们再给自定义控件加上几个<a>标签,让<a>也可以提交表单(就是触发事件),填写如下代码。
 
protected   override   void  CreateChildControls()
        
{
//省略。。。
this.Controls.Add(new LiteralControl("<BR><a id=\"aa\" href=\"javascript:__doPostBack('EventTest1$btn','')\">aa</a>"));
}


    运行OK。然后我们修改一下:__doPostBack的第二个参数,
 
< a id = \ " aa\ "  href = \ " javascript:__doPostBack('EventTest1$btn','1')\ " > aa </ a > " )


    奇怪,再次运行的时候出现了异常,看来不让这么做呀。

    依赖别人是不行了,必须要实现自定义控件自己的事件了。我们请来 IPostBackEventHandler 帮忙。同时<a>的href修改成
 
this .Controls.Add( new  LiteralControl( " <BR><a id=\ " a1\ "  href=\ " javascript:__doPostBack( ' "+ this.ClientID  +" ' , ' 1 ' )\ " >[1]</a> " ));
            
this .Controls.Add( new  LiteralControl( " &nbsp;<a id=\ " a2\ "  href=\ " javascript:__doPostBack( ' " + this.ClientID + " ' , ' 2 ' )\ " >[2]</a> " ));
            
this .Controls.Add( new  LiteralControl( " &nbsp;<a id=\ " a3\ "  href=\ " javascript:__doPostBack( ' " + this.ClientID + " ' , ' 3 ' )\ " >[3]</a> " ));
            
this .Controls.Add( new  LiteralControl( " &nbsp;<a id=\ " a4\ "  href=\ " javascript:__doPostBack( ' " + this.ClientID + " ' , ' 4 ' )\ " >[4]</a> " ));

在实现 RaisePostBackEvent 函数 
 
public   void  RaisePostBackEvent( string  Index)
        
{
            Label lbl 
= (Label)this.FindControl("lbl");
            lbl.Text 
+= "自己的事件:" + Index;
        }


    再次运行,OK。同时我们也得到了<a>传递过来的数字(页号)。

    还有一个 IPostBackDataHandler接口,由于暂时没不需要,所以没有研究,等用到的时候在研究。
----------------------------------------------------------------------

var  theForm  =  document.forms[ ' form1 ' ];
if  ( ! theForm)  {
    theForm 
= document.form1;
}

function  __doPostBack(eventTarget, eventArgument)  {
    
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value 
= eventTarget;
        theForm.__EVENTARGUMENT.value 
= eventArgument;
        theForm.submit();
    }

}


    如果您打开IE的“查看源文件”,会看到这个js函数,这是怎么来的呢?这个是button的事件带来的,虽然后面的代码并不需要button了,但是我比较懒,不想自己输出这个js函数,所以还是保留了button的事件。

    
    好像还是说的不太清楚。自定义控件的事件已经整理清楚了,我可以修改分页控件里的代码了,原来写的比较混乱。分页控件的下一个版本(v2.0.0.3)将增加两个事件,这样就可以向吴旗娃的分页控件那样灵活使用了。

附完整代码:

namespace  JYK.Controls.Page
{
    [DefaultProperty(
"Text")]
    [ToolboxData(
"<{0}:EventTest runat=server></{0}:EventTest>")]
    
public class EventTest : WebControl , INamingContainer,IPostBackEventHandler  
    
{
        
public event EventHandler myClick
        
{
            add
            
{
                Events.AddHandler(
this, value);
            }

            remove
            
{
                Events.RemoveHandler(
this, value);
            }

        }


        
protected void TestClick(object sender,EventArgs e)
        
{
            EventHandler hd 
= (EventHandler)base.Events[this];
            
if (hd != null)
            
{
                hd(sender, e);
            }

        }


        
public void RaisePostBackEvent(string Index)
        
{
            Label lbl 
= (Label)this.FindControl("lbl");
            lbl.Text 
+= "自己的事件:" + Index;
        }


        
protected override void CreateChildControls()
        
{
            Label lbl 
= new Label();
            lbl.ID 
= "lbl";

            
this.Controls.Add(lbl);
            
this.Controls.Add(new LiteralControl("<BR>"));

            LinkButton btn 
= new LinkButton();
            btn.ID 
= "btn";
            btn.Text 
= "复合控件的事件测试";
            
this.Controls.Add(btn);

            
//给按钮添加内部事件

            btn.Click 
+= new EventHandler(btn_Click);

          
this.Controls.Add(new LiteralControl("<BR><a id=\"aa\" href=\"javascript:__doPostBack('EventTest1$btn','')\">aa</a>"));

            
this.Controls.Add(new LiteralControl("<BR><a id=\"a1\" href=\"javascript:__doPostBack('"+ this.ClientID  +"','1')\">[1]</a>"));
            
this.Controls.Add(new LiteralControl("&nbsp;<a id=\"a2\" href=\"javascript:__doPostBack('" + this.ClientID + "','2')\">[2]</a>"));
            
this.Controls.Add(new LiteralControl("&nbsp;<a id=\"a3\" href=\"javascript:__doPostBack('" + this.ClientID + "','3')\">[3]</a>"));
            
this.Controls.Add(new LiteralControl("&nbsp;<a id=\"a4\" href=\"javascript:__doPostBack('" + this.ClientID + "','4')\">[4]</a>"));

        }


        
/**//// 控件内部的事件,由现有的控件的事件触发
         void btn_Click(object sender, EventArgs e)
        
{
            Label lbl 
= (Label)this.FindControl("lbl");
            lbl.Text 
+= "控件内部的事件,hi";

            
//调用外部事件
            TestClick(sender, e);
        }


        
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();
                
//output.Write("<div id='" + this.ClientID + "Page' style='TEXT-ALIGN: center;width:90%'>");
                base.Render(output);
                
//output.Write("</div>");
            }

        }

    }

}




相关文章
|
6月前
|
JSON 缓存 Go
Golang 语言 Web 框架 beego v2 之控制器方法和输入输出数据
Golang 语言 Web 框架 beego v2 之控制器方法和输入输出数据
51 0
|
7月前
|
安全 中间件 Apache
【Web安全】不安全的HTTP方法
围绕渗透攻防层面来看不安全的HTTP方法漏洞的检测发现修复等手法。
251 1
|
8月前
vite环境引入web worker方法
在 vite 环境中使用 web worker 时,如果遇到生产环境中 worker.js 文件的 MIME 类型被识别为 text/html,导致报错无法运行的情况时,可以参考以下两种方法,原理都是避免编译时产出单独的 worker.js 文件。方法一worker文件不需要包装,引入时后缀增加 ?worker&inline,使用时直接 new ImportedWorker();self.
422 0
|
1月前
|
安全 测试技术 API
请描述在 Python WEB 开发中常用的测试方法。
请描述在 Python WEB 开发中常用的测试方法。
16 0
|
2月前
|
JavaScript 前端开发 API
「深入探究Web页面生命周期:DOMContentLoaded、load、beforeunload和unload事件」
在 Web 开发中,了解页面生命周期是非常重要的。页面生命周期定义了页面从加载到卸载的整个过程,包括各种事件和阶段。在本文中,我们将详细介绍四个关键事件:DOMContentLoaded、load、beforeunload 和 unload。我们将探讨这些事件的属性、API、应用场景,并提供一些代码示例和参考资料。
|
3月前
|
Web App开发 前端开发 JavaScript
Web前端性能测试方法
Web前端性能测试方法
|
3月前
|
移动开发 前端开发 JavaScript
web前端之ES6的实用深度解构赋值方法、复杂的解构赋值
web前端之ES6的实用深度解构赋值方法、复杂的解构赋值
29 1
|
3月前
|
搜索推荐 应用服务中间件 Apache
HTTP状态码301(永久重定向)不同Web服务器的配置方法
当用户或搜索引擎向服务器发出浏览请求时,服务器返回的HTTP数据流中头信息(header)中包含状态码301,以向用户表示该资源已经永久改变了位置。
84 2
|
5月前
|
存储 移动开发 搜索推荐
Web开发中会话跟踪的方法有哪些?
Web开发中会话跟踪的方法有哪些?
30 0
|
5月前
|
Web App开发 Linux UED
Web 网站 LCP 性能指标的度量方法
Web 网站 LCP 性能指标的度量方法
49 1