ASP.NET中定制自己的委托和事件参数类
本文笔记选自《庖丁解牛:纵向切入ASP.NET 3.5控件和组件开发技术》一书
一般在实际开发中,对于事件不需要传递数据信息时,像上面的KingTextBox控件的事件,在引发事件时传递的参数为EventArgs.Empty,如下所示:
OnTextChanged(EventArgs.Empty);
这是因为控件KingTextBox的TextChanged事件比较简单,这里不需要参数对象传递数据。但像一些复杂的控件比如GridView的按钮命令事件,必须得有参数命令表示单击了哪个按钮;翻页事件,需要EventArgs参数对象把当前页信息传递到页面后台代码的事件体的第二个参数中,然后开发人员根据此页参数从数据库取得对应页的数据;还有像ItemDataBound事件,也需要把当前Row信息和索引等数据作为EventArgs参数传递到事件实例中。
当遇到以上这些情况,我们就需要定义自己的事件参数类和委托,而不使用默认的System.EventArgs类。下面就以Grid控件的翻页功能说明一下定义事件参数类和委托的方法,请看以下代码:
/// <summary>
///
/// </summary>
public delegate void GridPageChangedEventHandler(object source, GridPage ChangedEventArgs e);
public class GridPageChangedEventArgs : System.EventArgs
{
public GridPageChangedEventArgs()
{
}
private int intCurrentPageIndex;
public new int CurrentPageIndex
{
get { return intCurrentPageIndex; }
set { intCurrentPageIndex = value; }
}
private int intPageCount;
public new int PageCount
{
get { return intPageCount; }
set { intPageCount = value; }
}
private int intPageSize;
public new int PageSize
{
get { return intPageSize; }
set { intPageSize = value; }
}
}
以上代码定义了一个存储翻页相关信息的参数类,此参数类派生于System.EventArgs类,在这里系统不强制要求一定继承于该类,不继承它也是可以的,但继承于该类有一点好处。先看一下System.EventArgs基类的代码:
/// <summary>
///
/// </summary>
public class EventArgs
{
//表示没有事件数据的事件
public static readonly EventArgs Empty;
//初始化 System.EventArgs 类的新实例
public EventArgs();
}
EventArgs中除了一个构造方法外,还有一个它本身类型的Empty属性,从这里可以知道前面在调用时通过OnTextChanged(EventArgs.Empty);格式,把EventArgs.Empty作为空参数传入事件引发方法时的用途了。这里要说明的是如果我们的GridPageChangedEventArgs类是从EventArgs继承而来,则不但可以传递GridPageChangedEventArgs类对象,而且可以使用GridPageChangedEventArgs.Empty的形式传递空参数对象。
在GridPageChangedEventArgs方法体中定义了一些属性;分别表示当前页(CurrentPageIndex)、页总数(PageCount)和页尺寸(PageSize)。这些都是我们自定义的页信息数据。
代码中的这句:
public delegate void GridPageChangedEventHandler(object source, GridPage ChangedEventArgs e);
定义了一个委托GridPageChangedEventHandler。该委托可以指定这样的一个事件方法:第一个参数为object类型,第二个参数即为上面我们定义的页参数类对象GridPageChanged EventArgs。在注册事件时,该委托可以保证在页面后面代码中自动产生的事件体的两个参数类型与自己的两个参数类型一致。下面是在页面中注册的事件后台代码:
protected void Grid1_PageIndexChanged(object source,GridPageChangedEventArgs e)
{
int intCurrentPageIndex = e.CurrentPageIndex;
int intPageSize = e.PageSize;
//获取数据逻辑
}
可以看到第二个参数类型即我们定义的GridDocPageChangedEventArgs类型,在事件方法体中,可以直接通过e.CurrentPageIndex和e.PageSize获取数据,这种应用就比较多了。
现在页参数对象和委托定义好了,下面说一下在主控件内部是如何应用它们的。声明事件代码如下:
/// <summary>
///
/// </summary>
private new static readonly object EventPageIndexChanged = new object();
[Category("Action"), Description("翻页事件")]
public event GridPageChangedEventHandler PageIndexChanged
{
add
{
base.Events.AddHandler(Grid.EventPageIndexChanged, value);
}
remove
{
base.Events.RemoveHandler(Grid.EventPageIndexChanged, value);
}
}
这里继续采用5.3.1小节讲的高效率事件集合列表对象base.Events,事件的名称为PageIndexChanged,委托类型为之前我们定义的委托类型GridPageChangedEventHandler。
引发事件的核心代码如下:
/// <summary>
///
/// </summary>
protected override bool OnBubbleEvent(object source, EventArgs e)
{
bool handled = false;
if (e is GridCommandEventArgs)
{
if ((((GridCommandEventArgs)(e)).CommandSource) is LinkButton)
{
LinkButton lb=((LinkButton)(((GridCommandEventArgs)(e)). Command Source));
if (lb.CommandName == "Page")
{
if (lb.CommandArgument == "ButtonFirst")
{
GridPageChangedEventArgs ee = new GridPageChangedEventArgs();
if (this.CurrentPageIndex != 0)
{
this.CurrentPageIndex = 0;
ee.CurrentPageIndex = this.CurrentPageIndex;
ee.PageCount = this.PageCount;
ee.PageSize = this.PageSize;
this.OnPageIndexChanged(ee);
}
handled = true;
}
if (lb.CommandArgument == "ButtonNext")
{
GridPageChangedEventArgs ee = new GridPageChangedEventArgs();
if (this.CurrentPageIndex < this.PageCount - 1)
{
this.CurrentPageIndex += 1;
ee.CurrentPageIndex = this.CurrentPageIndex;
ee.PageCount = this.PageCount;
ee.PageSize = this.PageSize;
this.OnPageIndexChanged(ee);
}
handled = true;
}
if (lb.CommandArgument == "ButtonPrev")
{
GridPageChangedEventArgs ee = new GridPageChangedEventArgs();
if (this.CurrentPageIndex > 0)
{
this.CurrentPageIndex -= 1;
ee.CurrentPageIndex = this.CurrentPageIndex;
ee.PageCount = this.PageCount;
ee.PageSize = this.PageSize;
this.OnPageIndexChanged(ee);
}
handled = true;
}
if (lb.CommandArgument == "ButtonLast")
{
GridPageChangedEventArgs ee = new GridPageChangedEventArgs();
if (this.CurrentPageIndex != this.PageCount - 1)
{
this.CurrentPageIndex = this.PageCount - 1;
ee.CurrentPageIndex = this.CurrentPageIndex;
ee.PageCount = this.PageCount;
ee.PageSize = this.PageSize;
this.OnPageIndexChanged(ee);
}
handled = true;
}
}
}
}
return handled || base.OnBubbleEvent(source, e);
}
以上OnBubbleEvent方法主要应用于复合控件中,采用冒泡形式处理子控件事件,后面介绍复合控件冒泡处理事件机制时再详细讲解此方法。另外,在控件的翻页栏中预先放置了四个翻页功能的按钮,分别表示“首页”、“上一页”、“下一页”、“末页”,并设置它们的属性CommandName都为“Page”,CommandArgument分别为“ButtonFirst”,“ButtonPrev”,“ButtonNext”,“ButtonLast”。
这样就可以根据按钮的命令和参数确定执行什么样的逻辑。这里仅拿按钮“下一页”(Command="Page"&&CommandArgument="ButtonNext")为例解释一下代码逻辑:
/// <summary>
///
/// </summary>
if (lb.CommandArgument == "ButtonNext")
{
GridPageChangedEventArgs ee = new GridPageChangedEventArgs();
if (this.CurrentPageIndex < this.PageCount - 1)
{
this.CurrentPageIndex += 1;
ee.CurrentPageIndex = this.CurrentPageIndex;
ee.PageCount = this.PageCount;
ee.PageSize = this.PageSize;
this.OnPageIndexChanged(ee);
}
handled = true;
}
代码中首先定义一个页参数类对象,然后通过条件语句判断当前是否是最后一页,如果不是最后一页,则从主控件上读取当前页信息(当前页、页数、页记录数),并赋值给GridPageChangedEventArgs对象,然后以页参数对象作为参数调用this.OnPageIndexChanged方法引发事件。另外,注意LinkButton的CommandName和CommandArgument属性的组合用法。
最后,看一下OnPageIndexChanged方法代码:
/// <summary>
/// 获得本书更多内容,请看:
/// http://blog.csdn.net/ChengKing/archive/2008/08/18/2792440.aspx
/// </summary>
protected new void OnPageIndexChanged(GridPageChangedEventArgs e)
{
GridPageChangedEventHandler handler1 = (GridPageChangedEventHandler)base. Events[Grid.EventPageIndexChanged];
if (handler1 != null)
{
handler1(this, e);
}
}
此方法的功能是从base.Events对象中取出以Grid.EventPageIndexChanged为Key的事件引用句柄,假如句柄不为null(开发人员注册了翻页事件),则引发事件方法体。
最后,说明非常重要的一点:如果自定义了事件参数类,并要求在开发人员注册的事件体中自动显示改变参数对象的类型,如:
protected void Grid1_PageIndexChanged(object source, GridPageChangedEventArgs e)
{
//… …
}
中的第二个参数显示为GridPageChangedEventArgs类型,而不是默认的EventArgs类型,我们也必须定义自己的委托(如本例定义了委托GridPageChangedEventHandler);而默认的委托EventHandler对应的参数类型为基类System.EventArgs,即如果这里将默认的委托EventHandler和GridPageChangedEventArgs类一起使用的话,则生成以下的代码语句:
protected void Grid1_PageIndexChanged(object source, EventArgs e)
{
//… …
}
可以看出参数变为EventArgs类型了。这样就不能利用我们自己定义的GridPage ChangedEventArgs类中的数据了。虽然可以使用(GridPageChangedEventArgs)EventArgs的方式转换一下也可以取得GridPageChangedEventArgs对象中的数据,但据笔者了解还没有开发人员这么用,因为没有人知道还有个GridPageChangedEventArgs类。
这一节主要讲解如何定制自己的参数类和委托,并以Grid的分页功能为例演示其在实际开发中的应用。下一节开始讲解复合控件的事件机制。
ASP.NET中定制自己的委托和事件参数类的更多相关文章
- (转)客户端触发Asp.net中服务端控件事件
第一章. Asp.net中服务端控件事件是如何触发的 Asp.net 中在客户端触发服务端事件分为两种情况: 一. WebControls中的Button 和HtmlControls中的Type为su ...
- Servlet实现asp.net中的Global.asax启动事件(Servlet和Listener使用)
1.Java Web中没有像asp.net的全局启动事件,但是可以通过web.xml中的load-on-startup节点来控制Servlet的开机启动和启动次数.web.xml详细配置参考:http ...
- 使用javaScript解决asp.net中mvc使用ajax提交数组参数的匹配问题
想到在asp.net的mvc中如果使用ajax向服务端传递参数时如果参数是一个类或者是个数组(或List集合)以及更复杂的对象时,服务端总是会发生取不到值的情况,当然网上也有很多解决的例子,但都是在服 ...
- Asp.Net中调用存储过程并返回输出参数
/// <summary> /// 调用存储过程返回参数 /// </summary> /// <param name="orderId">&l ...
- ASP.NET中常用的几个李天平开源公共类LTP.Common,Maticsoft.DBUtility,LtpPageControl
ASP.NET中常用的几个开源公共类: LTP.Common.dll: 通用函数类库 源码下载Maticsoft.DBUtility.dll 数据访问类库组件 源码下载LtpPageC ...
- ASP.NET中常用的几个李天平开源公共类LTP.Common,Maticsoft.DBUtility,LtpPageControl (转)
ASP.NET中常用的几个开源公共类: LTP.Common.dll: 通用函数类库 源码下载Maticsoft.DBUtility.dll 数据访问类库组件 源码下载LtpPageC ...
- ASP.net中DateTime获取当前系统时间的大全
在c# / ASP.net中我们可以通过使用DataTime这个类来获取当前的时间.通过调用类中的各种方法我们可以获取不同的时间:如:日期(2008-09-04).时间(12:12:12).日期+时间 ...
- 【转】C# 中的委托和事件
阅读目录 C# 中的委托和事件 引言 将方法作为方法的参数 将方法绑定到委托 事件的由来 事件和委托的编译代码 委托.事件与Observer设计模式 .Net Framework中的委托与事件 总结 ...
- 关于asp.net中页面事件加载的先后顺序
一.ASP.NET 母版页和内容页中的事件 母版页和内容页都可以包含控件的事件处理程序.对于控件而言,事件是在本地处理的,即内容页中的控件在内容页中引发事件,母版页中的控件在母版页中引发事件.控件事件 ...
随机推荐
- 学习笔记_Java_day13_JSP三大指令()
JSP指令 1 JSP指令概述 JSP指令的格式:<%@指令名 attr1=”” attr2=”” %>,一般都会把JSP指令放到JSP文件的最上方,但这不是必须的. JSP ...
- 注册dll
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, Syste ...
- Solr 1.3 安装步骤
可以通过以下三种方式之一设置 Solr 的主位置: 1.设置 java 系统属性 solr.solr.home (没错,就是 solr.solr.home). 2.配置 ...
- OC与Swift的区别三(条件语句)
11.swift中的switch结构 区别一: oc中switch条件只可以放整数 swift中switch条件可以放几乎任何数据类型 区别二: oc中每一个case中应有break,如果没有brea ...
- javascript 函数学习
1.自以为好的部分,更多访问: http://www.runoob.com/js/js-tutorial.html 2.this 3.new 4.闭包 5.自执行
- AngularJS2学习
@Input @Input是用来定义模块的输入的,用来让父模块往子模块传递内容: @Component({ selector: 'bank-account', template: ` Bank Nam ...
- webstorm的默认project编码为系统编码GBK.
使用新的IDE,而不会设置,会给你带来灾难. 如下为我是用webstorm时遇到的文件编码问题. 纳闷很久,终于发现是IDE的设置问题. 参考
- 导入外部jar包的方法
注:使用的编译平台为eclipse <算法>一书中需要引入外部jar包(algs4.jar),因此特地去学了下导入外部jar包的方法.步骤如下: 1.先将algs4.jar拷到j如下路径: ...
- IF EXIST: The syntax of the command is incorrect.
Batch 脚本中使用 IF EXIST 语句时,总是提示 The syntax of the command is incorrect. 原始 bat 脚本如下: ECHO OFF SET proj ...
- MySQL配置文件详解
MYSQL 配置文件详解 “全局缓存”.“线程缓存”,全局缓存是所有线程共享,线程缓存是每个线程连接上数据时创建一个线程(如果没有设置线程池),假如有200连接.那就是200个线程,如果参数设定值是1 ...