在ASP.NET的复合组件中实现冒泡处理机制

本文节选自《庖丁解牛:纵向切入ASP.NET 3.5控件和组件开发技术》一书

在复合控件中,如果子控件之间结构比较复杂,并且很多情况下是多层次的结构,比如在GridView主控件中包括模板容器控件,模板容器控件中又包含命令按钮控件,且控件比较多,在这种情况下如果再使用前面讲的事件机制会比较麻烦;且代码看起来比较乱,因为要为每个按钮注册一个事件(GridView的按钮列的按钮数取决于每页的记录数,有多少行就有多少按钮)。
基于此,ASP.NET框架提供了冒泡法,即事件向上冒泡,其核心是使用.NETFramework提供的事件上传机制。这种机制允许子控件将事件沿其包容层次结构向上传播,而不是由每个命令按钮引发事件。在事件上传过程中由我们确定什么时候引发自定义的事件。通过响应这一事件,可以不必为子控件分别编写事件处理方法。
冒泡法的实现,主要是利用Control基类中专门用于事件上传的两个方法OnBubbleEvent和RaiseBubbleEvent。基类Control中这两个方法的原声明代码如下:
/// <summary>
/// 获得本书更多内容,请看:
/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// </summary>
protected virtual bool OnBubbleEvent(object source, EventArgs args)
{
    return false;
}

protected void RaiseBubbleEvent(object source, EventArgs args)
{
    for (Control control = this.Parent; control != null; control = control.Parent)
    {
        if (control.OnBubbleEvent(source, args))
        {
            return;
        }
    }
}
OnBubbleEvent方法用于引发自定义事件,并通过返回布尔值指定子控件的事件是否沿复合控件层次结构继续向上传递。参数source表示事件源(如Button),参数args表示包含事件数据的EventArgs对象(当指定按钮的CommandName,系统会自动创建它的CommandEventArgs对象,该对象类型的基类为EventArgs)。如果需要处理当前容器控件冒泡事件,则要重写OnBubbleEvent事件,在OnBubbleEvent重写方法中引发自己的事件,处理完自己的事件逻辑后,最终要返回一个布尔值,来决定是否让冒泡机制继续沿着容器结构向上传递。Control基类虚方法的默认值为false。
RaiseBubbleEvent方法用于将所有事件源及其信息分配给控件的父级。有一点很重要,它不能被重写,需要调用它时直接调用即可。
下面就基于冒泡法,把SearchControl的按钮事件引发用冒泡法来实现,控件命名为SearchControlBubbleUp。实现起来非常简单,由于只是引发事件方式不同,仅需要针对变更的部分,修改一下引发事件相关的代码,即把:

btnSearch.Click += new EventHandler(btnSearch_Click);

protected virtual void OnButtonSearchClick(SearchEventArgs e)
    {
        SearchEventHandler ButtonSearchClickHandler = (SearchEventHandler) Events[ButtonSearchClickObject];
        if (ButtonSearchClickHandler != null)
        {
            ButtonSearchClickHandler(this, e);
        }
    }

修改为:

btnSearch.CommandName = "ButtonSearchClick";

protected override bool OnBubbleEvent(object sender, EventArgs e)
    {
        bool handled = false;
        if (e is CommandEventArgs)
        {
            CommandEventArgs ce = (CommandEventArgs)e;
            if (ce.CommandName == "ButtonSearchClick")
            {
                SearchEventArgs args = new SearchEventArgs();
                args.SearchValue = this.Text;
                OnButtonSearchClick(args);
                handled = true;
            }
        }
        this.RaiseBubbleEvent(sender, e);
        return handled;
    }

以上代码中,原来的SearchControl控件是通过注册Button的标准事件来完成的,而在这一节的示例控件SearchControlBubbleUp中仅做了两个步骤:
  指定Button控件的CommandName属性。一般该属性经常与CommandArgument组合使用。
  重写OnBubbleEvent方法。在该方法中,首先取得参数对象,然后根据参数对象判断当前引发事件源是不是我们指定的按钮(属性CommandName是否等于“ButtonSearch Click”)。如果是我们指定的按钮,则引发调用主控件的事件OnbuttonSearchClick(args),并设置标志返回值的变量handled为true。在最后返回值之前调用了Control基类的RaiseBulleEvent方法,把事件源sender和e参数对象发送给控件的父级。
下面看一下SearchControlBubbleUp控件完整源代码,如下所示:
/// <summary>
/// 获得本书更多内容,请看:
/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// </summary>
[DefaultProperty("Text")]
[DefaultEvent("ButtonSearchClick")]
[ToolboxData("<{0}:SearchControlBubbleUp runat=server></{0}:SearchControlBubbleUp>")]
public class SearchControlBubbleUp : CompositeControl
{
    private Button btnSearch;
    private TextBox tbSearchText;

[Category("搜索")]
    [DefaultValue("")]
    [Description("获取文本框的值")]
    public string Text
    {
        get
        {
            this.EnsureChildControls();
            return tbSearchText.Text;
        }
    }

private static readonly object ButtonSearchClickObject = new object();
    public event SearchEventHandler ButtonSearchClick
    {
        add
        {
            base.Events.AddHandler(ButtonSearchClickObject, value);
        }
        remove
        {
            base.Events.RemoveHandler(ButtonSearchClickObject, value);
        }
    }

protected override void CreateChildControls()
    {
        this.Controls.Clear();
        btnSearch = new Button();
        btnSearch.ID = "btn";
        btnSearch.Text = "搜索";
        btnSearch.CommandName = "ButtonSearchClick";

tbSearchText = new TextBox();
        tbSearchText.ID = "tb";
        this.Controls.Add(btnSearch);
        this.Controls.Add(tbSearchText);
    }

protected virtual void OnButtonSearchClick(SearchEventArgs e)
    {
        SearchEventHandler ButtonSearchClickHandler = (SearchEventHandler)
        Events[ButtonSearchClickObject];
        if (ButtonSearchClickHandler != null)
        {
            ButtonSearchClickHandler(this, e);
        }
    }

protected override bool OnBubbleEvent(object sender, EventArgs e)
    {
        bool handled = false;
        if (e is CommandEventArgs)
        {
            CommandEventArgs ce = (CommandEventArgs)e;
            if (ce.CommandName == "ButtonSearchClick")
            {
                SearchEventArgs args = new SearchEventArgs();
                args.SearchValue = this.Text;
                OnButtonSearchClick(args);
                handled = true;
            }
        }
        this.RaiseBubbleEvent(sender, e);
        return handled;
    }

protected override void Render(HtmlTextWriter output)
    {
        output.AddAttribute(HtmlTextWriterAttribute.Border, "0px");
        output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "5px");
        output.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0px");
        output.RenderBeginTag(HtmlTextWriterTag.Table);
        output.RenderBeginTag(HtmlTextWriterTag.Tr);
        output.RenderBeginTag(HtmlTextWriterTag.Td);
        tbSearchText.RenderControl(output);
        output.RenderEndTag();
        output.RenderBeginTag(HtmlTextWriterTag.Td);
        btnSearch.RenderControl(output);
        output.RenderEndTag();
        output.RenderEndTag();
        output.RenderEndTag();
    }
}
SearchControlBubbleup控件在页面中的使用方法与SearchControl完全一样。
使用冒泡机制时要注意分清楚控件的层次结构,一般开发列表控件等比较复杂的控件时,比如所有的编辑、删除等命令列的处理经常会采用此机制。
该控件现在已经能够完成基本的搜索功能了,但还缺少一个比较智能的功能。下一节我们将完善该控件,完成它的最终版本。

在ASP.NET的复合组件中实现冒泡处理机制相关推荐

  1. ASP.NET的WebFrom组件LinkButton编程

    作者:阿虎  来自:yesky 在ASP.NET的WebForm组件中的LinkButton组件也是一个服务器端的组件,这个组件有点类似于HTML中的<A>标识符.它的主要作用是就是在AS ...

  2. JSF 2 简介,第 2 部分: 模板及复合组件

    转自:http://www.ibm.com/developerworks/cn/java/j-jsf2fu2/ 用 JavaServer Faces 2 实现可扩展 UI 级别: 中级 David G ...

  3. ASP.NET 2.0 AJAX中Webservice调用方法示例

    ASP.NET 2.0 AJAX中能够在客户端js中很方便地调用服务器Webservice,以下为一些调用的示例.笔者安装的ASP.NET 2.0 AJAX 版本为AJAX November CTP. ...

  4. ASP.NET2.0自定义控件组件开发 第六章 深入讲解控件的属性

    深入讲解控件的属性持久化(一) 系列文章链接: ASP.NET自定义控件组件开发 第一章 待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 ASP.NET自定义控件组件开发 第一章 第 ...

  5. ASP.NET Web 页面生命中的一天

    ASP.NET Web 页面生命中的一天  Dino Esposito Wintellect 2003 年 8 月 适用于: Microsoft® ASP.NET 摘要:了解为 ASP.NET Web ...

  6. Asp.Net上传组件

    Asp.Net上传组件 上传功能在Web开发中经常用到,因此花点时间写了个简单的组件.组件支持以下功能: 1.支持文件存储节点分组,同一分组内的节点随机存储(默认),亦可自选择节点进行存储. 2.存储 ...

  7. [Asp.net]AspNetPager分页组件

    引言 在基于Asp.net的内网系统中,分页功能是最常用的,用的最多的组件就是AspNetPager. AspNetPager 官网:http://www.webdiyer.com/aspnetpag ...

  8. react --- 复合组件,传递属性

    组件复合 复合组件给予你足够的灵活去定义组件的外观和行为,而且是以一种明确和安全的方式进行. 如果组件间有公用的非UI逻辑,将它们抽取为JS模块导入使用而不是继承它 /src/components/C ...

  9. 一张大图了解ASP.NET Core 3.1 中的Authentication与Authorization

    下面是一张ASP.NET Core 3.1 中关于Authentication与Authorization的主流程框线图,点击这里查看全图:https://johnnyqian.net/images/ ...

  10. ASP.Net Core 2.0中的Razor Page不是WebForm

    随着.net core2.0的发布,我们可以创建2.0的web应用了.2.0中新东西的出现,会让我们忘记老的东西,他就是Razor Page.下面的这篇博客将会介绍ASP.Net Core 2.0中的 ...

最新文章

  1. GOF23设计模式(创建型模式) 原型模式
  2. clojurescript_为什么ClojureScript在NPM上如此出色
  3. SpringCloud服务消费者第一次调用出现超时问题的解决方案
  4. 动态管理配置文件扩展接口EnvironmentPostProcessor
  5. 嵌入式计算机的特点和应用,以下描述中,()不是嵌入式操作系统的特点。A.面向应用,可以进行裁剪和移植B.用 - 信管网...
  6. 工作中应用计算机,浅谈计算机在我国计工作中的应用与发展.doc
  7. 现在五年期定期利率在五以上的银行有哪些?
  8. 三大电信运营商携号转网数据_携号转网数据出炉!转出移动最多,近五成转入电信...
  9. python 题目识别截图切分(有道API接口题目坐标识别、PIL截图)
  10. 17.敏捷项目管理流程实例 - 整体流程框架
  11. WICED™ SMART Software Development Kit
  12. aria2 txt导入_共一章 · mac下使用Aria2教程-迅雷和百度盘终极解决方案 · 看云
  13. WIN10使用VEH+硬件断点实现不修改代码完成破解
  14. Centos8关闭防火墙
  15. 如何提升自己(一) 谈学习
  16. java BigDecimal
  17. 5个适合新手练习的Python刷题网站
  18. 2021春招面经系列--计算机网络和操作系统
  19. SSM毕设项目某企业危化品信息管理系统bf339(java+VUE+Mybatis+Maven+Mysql)
  20. php class 构造_PHP 类与构造函数解析

热门文章

  1. 如何保证ArrayList线程安全
  2. 想加入一行代码吗?使用code标签
  3. C++ container member map
  4. 转:PyDev for Eclipse 简介
  5. (对比PDF)Adobe Acrobat DC 离线对比PDF、draftable.com/compare 在线对比PDF
  6. adb命令获取app布局文件xml
  7. webpack + react
  8. luoguP3723 HNOI2017 礼物
  9. 面向接口的开发到面向对象的编程
  10. docker 拷贝镜像文件