服务器控件开发 - 事件机制(3)

ASP.NET服务器控件事件机制
本文详细介绍了ASP.NET服务器控件的事件机制,包括如何为控件添加事件支持、事件注册的两种方式以及Asp.net2.0中页面模型自动绑定事件的特性。文章还探讨了基于System.ComponentModel.EventHandlerList类的事件实现模式,并对比了传统事件实现模式的优缺点。
    在上一篇的基础上, 我们来看看如何为我们的服务器控件添加事件支持。 丰富的事件支持能让控件的使用者最大限度的参与控件的生命周期,最大限度得提高控件的重用性。
     每一个服务器控件都从Control基类继承了 OnInit, OnLoad, OnPreRender, and OnUnLoad 等 4 个事件. 在页面开发中, 开发人员可以通过2种方式来注册ASP.NET事件.
1. 通过声明的方式
     <asp:Button id="button1" OnClick="button1_Click" Text="Submit" runat="server" />
2. 通过编程的方式
     button1.Click += new EventHandler(this.button1_Click);
    另外一点需要注意的是, 在Asp.net 2.0 里面. 页面模型自动将Page_Init, Page_Load, Page_PreRender, and Page_Unload 4 个方法绑定到页面对应的事件.
而不需要显式的声明. 这个特性是通过在页面声明中加入 AutoEventWireup="true" 来实现的. 如果发现页面不触发Page_Load 事件. 一个可能的原因就是
AutoEventWireup 的值被设为 False.
    在C# 中 定义一个典型的事件代码如下:
Code
    public delegate void ClickEventHanlder(object sender, EventArgs e);
    
public event ClickEventHanlder OnClickEvent = null;

    
public void RaiseEvent()
    
{
        
if (OnClickEvent != null)
        
{
            OnClickEvent(
this, EventArgs.Empty);
        }

    }
    然而, 在ASP.NET 中, 微软并没有采用这样一种方式来定义事件.而是基于Web 开发的特点进行优化, 采用了另外一种方式. 书中提到了2 点之所以不采用
    经典事件实现模式的原因:
    1.  不管事件是否被注册到具体的方法, 每当我们定义一个事件成员, 比如说    public event ClickEventHanlder OnClickEvent = null;  编译器都会为
        之生成一个私有的代理,比如: delegate void ClickEventHanlder(object sender, EventArgs e). 一但事件数目比较多, 将会浪费很多宝贵的内存空间
    2.  编译器会为经典事件模式生成一大堆的线程同步的代码. 这样不但降低了执行效率而且是毫无必要的, 因为页面开发者很少在单个页面使用多线程.
 
现在让我们来看一下针对于Asp.net 的优化的 基于System.ComponentModel.EventHandlerList 类的事件实现模式, 
首先来看看Control 中 OnInit 事件的实现.
 1. 声明一个 EventHandlerList  类型的事件索引,用来保存代理列表。
Code
  private EventHandlerList _events;
    
protected EventHandlerList Events {
    
get {
        
if (_events == null) {
            _events 
= new EventHandlerList();
        }
        
return _events;
        }
    }
 Control 基类为每一个事件定义了一个静态只读的键, 用来从EventHandlerList 中获取事件代理, 或者将事件代理添加到事件列表上.
Code
protected static readonly object EventInit = new object();
      注意这个键是静态共享的, 这意味着所有的控件的所有实例共享这个键.

 2. Control 基类使用一个事件属性来定义事件. 而不是使用事件成员.
Code
   public event EventHandler Init {
    add {
        Events.AddHandler(EventInit, value);
    }
    remove {
        Events.RemoveHandler(EventInit, value);
    }
   }

       当用户向事件列表添加一个事件代理, Events 类首先通过事件的键 判断 事件是否已经添加。 如果未添加, 则添加,如果键已经存在, 则将代理方法添加到键所对应的代理的代理列表上。
       当用户再事件列表移除一个事件代理, 过程刚好相反。

  3. 定义一个事件触发器, 通过一个hook, 调用代理方法。

Code
  protected virtual void OnInit(EventArgs e) { 
    EventHandler initHandler 
= (EventHandler)Events[EventInit];
    
if (initHandler != null) {
        initHandler(
this, e);
    }  
   }


 最后  在页面的特定阶段触发事件, OnInit 事件的触发可以参考我第一篇当中的 InitRecursive方法

通过以上方式就可以任意的为我们的自定义控件添加事件。 而不需要去考虑任何的性能问题。

下一篇  : 服务器控件的 PostBack 机制。


转载于:https://www.cnblogs.com/wwwyfjp/archive/2008/07/04/1235784.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值