写自定义控件已经好久了,也有几个用得时间比较长的,但是对于“事件”一直是比较模糊,没有很详细的理解。
    
    最近升级分页控件,由于原来使用的是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>");
            }
        }
    }
}

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

  1. 【v-on】一个元素绑定多个事件以及一个事件绑定多个函数的两种写法

    本文代码主要讲述了v-on绑定事件函数传参,一个元素绑定多个事件的两种写法,一个事件绑定多个函数的两种写法,修饰符的使用. <!DOCTYPE html> <html lang=&q ...

  2. Web 之 html 如何显示隐藏Html元素的两种方法简单整理

    Web 之 html 如何显示隐藏Html元素的两种方法简单整理 目录 Web 之 html 如何显示隐藏Html元素的两种方法简单整理 一.简单介绍 二.实现原理 三.注意事项 四.代码示例 一.简 ...

  3. linux中添加一个用户到指定用户组的两种方式,修改一个用户到指定用户组的一种方式...

    添加一个用户到指定用户组: gpasswd –a 用户名 组名 usermod –G 组名 用户名 //第一种:gpasswd –a 用户名 组名 [root@localhost ~]# id use ...

  4. nuxt添加.html,Nuxt内导航栏的两种实现方式

    方式一 | 通过嵌套路由实现 在pages页面根据nuxt的路由规则,建立页面 1. 创建文件目录及文件 根据规则,如果要创建子路由,子路由的文件夹名字,必须和父路由名字相同 所以,我们的文件夹也为i ...

  5. Django 后台admin管理页面添加简易导出/下载数据功能的两种方法

    在Django中有时候需要在后台界面需要用到导出数据的功能,对于功能要求比较高的可以直接使用Import_Export库来完成.但是对于一些简单的数据导出,可以直接自定义一些简单的函数来实现导出数据. ...

  6. svg鼠标响应事件的四种方法(其中两种可支持火狐)

    svg鼠标响应事件的四种方法 鼠标响应事件的四种方法,以click事件为例. Mouse Events - SMIL <?xml version="1.0" encoding ...

  7. ppt模板怎样用到html中,如何添加套用 PPT 模板?教你两种方法

    如果你想要提升幻灯片的质量,需要注意的细节有很多,除了进行图文排版,还可以套用PPT模板,这样就不用思考划分标题栏.内容区域,可以节省时间.现在问题来了,如何导入PPT模板?很简单,大家可以试试下面两 ...

  8. Web Control 开发系列(三) 解析IPostBackEventHandler和WebForm的事件机制

    WebForm最大的魅力大概就是它自己的一套事件处理机制了,要做一个好的Control,必须深入理解这套机制,只有这样才可以让我们的Control有一整套Professional的Event,而IPo ...

  9. 添加事件的兼容性写法

    通常,我们为某个控件元素添加事件时,用的是: 1 ele.οnclick=fn1(){}; 2 或者 3 ele.οnclick=fn1; //此时不需要加括号,调用的是整个方法而不是return的结 ...

最新文章

  1. java开发编程周末班_今天,Java编程周末提高班(第一期)正式结束
  2. 三菱modbusRTU通讯实例_干货 | 解析西门子系列PLC编程实例
  3. 主题:Centos6.4安装JDK
  4. libusb开发指南
  5. leetcode112. 路径总和
  6. 华为与五粮液签署战略合作协议
  7. Mysql - 解决Access denied for user ''@'localhost' to database 'mysql'问题
  8. AI、大数据、中台、AIoT、Fintech等十余场火热专题应有尽有,年度盛会BDTC 2019邀您共赴!...
  9. 接口协议之抓包分析 TCP 协议
  10. 20169219《linux内核原理与分析》第七周作业
  11. Filter过滤器|敏感词汇过滤
  12. 黑马程序员-银行业务调度系统
  13. 100个常用的 PHP 类库、资源和技巧小结
  14. 手绘图解:从零维到十维空间
  15. 入库管理系统示例代码
  16. k8s搭建 rabbitmq集群
  17. 混沌神经网络(Chaos Neural Network)
  18. 在笔记本电脑上运行塔克机器人的语音播报功能
  19. linux shell打印序号,Bash脚本编号生成器
  20. SVPWM过调制算法实现

热门文章

  1. 01-Vue博客后台管理页面框架搭建
  2. 【开发环境】Ubuntu 中使用 VSCode 开发 C/C++ ③ ( 创建工程目录 | 添加 C++ 源代码 | 代码自动提示 )
  3. 【Flutter】Flutter 混合开发 ( 简介 | Flutter 混合开发集成步骤 | 创建 Flutter Module )
  4. 【设计模式】中介者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
  5. 【错误记录】Flutter 构建报错 ( Because xxx requires SDK version >=2.12.0-0 <3.0.0, versio | Dart SDK 版本低 )
  6. delphi使用sqlite数据库时的中文路径问题
  7. Java数据库连接池实现原理
  8. 最常用的15大Eclipse开发快捷键技巧
  9. 多行列表右边距为零的实现方法
  10. Chapter18-Export and Import Utilities