ASP.NET自定义控件组件开发 第三章 为控件添加事件
2009-04-24 11:40
447 查看
本系列来自:http://www.chinaitz.com/html/2009/0307/398749.html
好了,我们之前以前开发一个控件。而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件。
ASP.NET的开发都是事件驱动的,现在我们就来为控件添加事件。在说事件之前,希望大家对C#的语法要熟悉,对委托很事件要懂。
其实定义事件的步骤很简单:
1.声明一个委托。
2.定义一个携带事件信息的类。
3.定义事件4.定义一个通事件发生后,通知其他对象的方法首先来理清一下我们的思路:
1.在下拉框中选中一个值,并且在输入框中也输入相应的值。
2.我们在页面点击“提交”按钮,按钮就触发我们自定义的一个事件Validate(验证输入信息的正确行)。
我们在提交的时候要把控件的信息传给服务器,所以我们要定义一个事件信息类,来携带事件发生时,把个信息类送到服务器。
事件定义如下:
1.定义一个携带事件信息的类。
2.声明一个委托。
3.定义事件
4.通事件发生后,通知其他对象的方法
这样几个步骤之后,控件的事件就写完了。大家试试!
前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是行不通。如果大家开发的是WinForm中的事件,之前的定义可能没有什么大的问题,只是在效率方法欠考虑而且,还是可以运行的。
下面我们就回到ASP.NET中的事件。
大家也许看了我们之前定义的事件,确实,事件一般是那么定义的,但是那样定义事件后的,运行起来的效率不搞,因为那样定义事件后,编译器在编译事件代码的时候,会自动的为我们加入很多多线程安全的代码,就是说,虽然我们只是定义几行代码,大但是编译器为我们做了很多额外的事情,当然,这样代码的运行的效率可想而知。
在很多的时候,我们自定义控件的事件不是需要考虑多线程安全等问题的,所我们就要改变代码,使其运行的更加好,我们就采用下面的方法:显示的申明事件:
还有就是:如果一个事件在事件列表(是一个hashtable)已经注册了,当页面上有两个相同我们自定义控件,我的控件的事件也只是在注册一次,效率也高了。
到这里一个事件就定义好了。现在做的事情就是要触发事件。即,点击“提交”按钮,就触发。我们先了理解一下流程:
点击“提交”,整个页面就向服务器提交了,之后就开始了页面的生命周期。
1.对页面进行解析,将原来页面中的源,如<asp:....></asp>这样的标记解析成相应的html代码,当把页面解析完之后,页面在服务器就是html的样式了。(我这里说的很粗略,没有必要说的那么详细)。
2.解析后的页面就开始检查,刚才是哪个控件引发的服务器回传,即,是点击了哪个按钮后,整个页面向服务器提交的,我们这里就是那个“提交”按钮。
3.解析后的页面检查“提交”按钮的name是否和控件(CreditCardForm)的name相同,如果相同。再检查控件 CreditCardForm实现了IPostBackEventHandler接口,如果实现了,就引发我们之前定义的事件。
这样,我们的控件就和真正的服务器控件没有两样了。(注意:上面的第3点:我们要按钮的name和CreditCardForm的name一样,这里的name我们无法用自己手动来设置他们的一样,因为CreditCardForm的名字是有页面来设置的,页面将其设置为:this.UniqueID,所以我们只能将按钮的名字设置为this.UniqueID,这样就可以了),所以我们要重写CreditCardForm5的一些属性:
还有,每一次页面提交给服务器后,解析页面的this.UniqueID都不一样。而且,如果在页面中同时有两个CreditCardForm,我们也要保证两个控件的其他控件,如输入框等等的name也不一样,所以要分别重写name。
这样以后,我们的控件就可以引发服务器回传了,即,当你点击“提交”按钮时,我们的浏览器的状态栏下面就有刷新的进度条了。
注意,还有一个问题啊,我们确实能够使得我们的控件向服务器提交信息,但是服务器怎么来得到我们的提交的信息呢?
并不是我们把信息向服务器提交后,就什么都不管了,然后服务器就”很听话的“进行验证。不是这样的,起码我们还要告诉服务器,我们提交了哪些要被验证的信息。
那么服务器这样接受到我们的信息,,很简单,只要实现一个接口就可以了--IPostBackDataHandler。
接口有两个方法,第一个就是LoadPostData方法,就是来获取我们的信息,并且判断我们这次提交的信息和上次有变化没有。
上面的方法返回一个布尔的值,如果返回true,就自动的调用下一个方法RaisePostDataChangedEvent,大家可以根据方法的英文看到他们的作用。
这里我们只是讲下LoadPostData方法,方法的完成写法是这样的:
看见方法不要害怕,方法的参数,前一个参数,我们不要管,只要看看后面的参数就可以了。
我们的信息的提交,都是在相应的输入框,下拉框中写好了,传给服务器的,其实是以:键值对,传了的.
键:就是我们输入框等的名字,name
值:就是输入的值。
其实NameValueCollection就是一个哈希表,来存放键值对的。
我们之前的所有输入的信息被包含成了一个NameValueCollection传到服务器,然后服务器就通过对应的“键”(name)来获取值,然后验证。
代码如下:
好了,我们之前以前开发一个控件。而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件。
ASP.NET的开发都是事件驱动的,现在我们就来为控件添加事件。在说事件之前,希望大家对C#的语法要熟悉,对委托很事件要懂。
其实定义事件的步骤很简单:
1.声明一个委托。
2.定义一个携带事件信息的类。
3.定义事件4.定义一个通事件发生后,通知其他对象的方法首先来理清一下我们的思路:
1.在下拉框中选中一个值,并且在输入框中也输入相应的值。
2.我们在页面点击“提交”按钮,按钮就触发我们自定义的一个事件Validate(验证输入信息的正确行)。
我们在提交的时候要把控件的信息传给服务器,所以我们要定义一个事件信息类,来携带事件发生时,把个信息类送到服务器。
事件定义如下:
1.定义一个携带事件信息的类。
1usingSystem; 2usingSystem.Collections.Generic; 3usingSystem.Text; 4 5namespaceCreditCardForm 6{ 7 publicclassValidateCreditCardFormEventArgs:EventArgs 8 { 9 privatestringpaymentMethod; 10 publicstringPaymentMethod 11 { 12 get 13 { 14 returnthis.paymentMethod; 15 } 16 } 17 18 19 privatestringcreditCardNo; 20 publicstringCreditCardNo 21 { 22 get 23 { 24 returnthis.creditCardNo; 25 } 26 } 27 28 29 privatestringcardholderName; 30 publicstringCardholderName 31 { 32 get 33 { 34 returnthis.cardholderName; 35 } 36 } 37 38 privateDateTimeexpirationDate; 39 publicDateTimeExpirationDate 40 { 41 get 42 { 43 returnthis.expirationDate; 44 } 45 } 46 47 48 publicValidateCreditCardFormEventArgs(stringpaymentmenthod,stringcreditcardno, 49 stringcardholdername,DateTimeexpirationdate) 50 { 51 this.paymentMethod=paymentmenthod; 52 this.creditCardNo=creditcardno; 53 this.cardholderName=cardholdername; 54 this.expirationDate=expirationdate; 55 } 56 } 57} 58
2.声明一个委托。
1usingSystem; 2usingSystem.Collections.Generic; 3usingSystem.Text; 4 5namespaceCreditCardForm 6{ 7 publicdelegatevoidValidateCreditCardFormEventHandler(objectsender,ValidateCreditCardFormEventArgsargs); 8} 9
3.定义事件
1 publiceventValidateCreditCardFormEventHandlerValidateCreditCardForm;
4.通事件发生后,通知其他对象的方法
1 2//这个方法是受保护的虚方法 3protectedvoidOnValidateCreditCardForm(ValidateCreditCardFormEventArgsargs) 4 { 5 if(ValidateCreditCardForm!=null) 6 handler(this,args); 7 }
这样几个步骤之后,控件的事件就写完了。大家试试!
前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是行不通。如果大家开发的是WinForm中的事件,之前的定义可能没有什么大的问题,只是在效率方法欠考虑而且,还是可以运行的。
下面我们就回到ASP.NET中的事件。
大家也许看了我们之前定义的事件,确实,事件一般是那么定义的,但是那样定义事件后的,运行起来的效率不搞,因为那样定义事件后,编译器在编译事件代码的时候,会自动的为我们加入很多多线程安全的代码,就是说,虽然我们只是定义几行代码,大但是编译器为我们做了很多额外的事情,当然,这样代码的运行的效率可想而知。
在很多的时候,我们自定义控件的事件不是需要考虑多线程安全等问题的,所我们就要改变代码,使其运行的更加好,我们就采用下面的方法:显示的申明事件:
1 2//其实其实一个辅助的变量,用来做Hashtable中的”键“ 3privatestaticobjectValidateCreditCardFormKey=newobject(); 4 publiceventValidateCreditCardFormEventHandlerValidateCreditCardForm 5 { 6 add 7 { 8 Events.AddHandler(ValidateCreditCardFormKey,value); 9 } 10 remove 11 { 12 Events.RemoveHandler(ValidateCreditCardFormKey,value); 13 } 14 } 15 16 17 protectedvoidOnValidateCreditCardForm(ValidateCreditCardFormEventArgsargs) 18 { 19 ValidateCreditCardFormEventHandlerhandler=Events[ValidateCreditCardFormKey] 20 asValidateCreditCardFormEventHandler; 21 if(handler!=null) 22 handler(this,args); 23 }
注意:其实就我们之前定义的事件的代码而言,编译器在在编译我们的代码的时候,也是编译成了上面的形式而且还额外的加上了一些安全的控制代码,这里,我们现在不要编译器生成,而是我们自己写出来,效率就高了。
还有就是:如果一个事件在事件列表(是一个hashtable)已经注册了,当页面上有两个相同我们自定义控件,我的控件的事件也只是在注册一次,效率也高了。
到这里一个事件就定义好了。现在做的事情就是要触发事件。即,点击“提交”按钮,就触发。我们先了理解一下流程:
点击“提交”,整个页面就向服务器提交了,之后就开始了页面的生命周期。
1.对页面进行解析,将原来页面中的源,如<asp:....></asp>这样的标记解析成相应的html代码,当把页面解析完之后,页面在服务器就是html的样式了。(我这里说的很粗略,没有必要说的那么详细)。
2.解析后的页面就开始检查,刚才是哪个控件引发的服务器回传,即,是点击了哪个按钮后,整个页面向服务器提交的,我们这里就是那个“提交”按钮。
3.解析后的页面检查“提交”按钮的name是否和控件(CreditCardForm)的name相同,如果相同。再检查控件 CreditCardForm实现了IPostBackEventHandler接口,如果实现了,就引发我们之前定义的事件。
这样,我们的控件就和真正的服务器控件没有两样了。(注意:上面的第3点:我们要按钮的name和CreditCardForm的name一样,这里的name我们无法用自己手动来设置他们的一样,因为CreditCardForm的名字是有页面来设置的,页面将其设置为:this.UniqueID,所以我们只能将按钮的名字设置为this.UniqueID,这样就可以了),所以我们要重写CreditCardForm5的一些属性:
1 protectedoverridestringSubmitButtonName 2 { 3 get 4 { 5 returnthis.UniqueID; 6 } 7 }
还有,每一次页面提交给服务器后,解析页面的this.UniqueID都不一样。而且,如果在页面中同时有两个CreditCardForm,我们也要保证两个控件的其他控件,如输入框等等的name也不一样,所以要分别重写name。
1protectedoverridestringPaymentMethodListName 2 { 3 get 4 { 5 returnthis.UniqueID+":PaymentMethod"; 6 } 7 } 8 9 protectedoverridestringCreditCardNoTextName 10 { 11 get 12 { 13 returnthis.UniqueID+":CreditCardNo"; 14 } 15 } 16 17 protectedoverridestringCardholderNameTextName 18 { 19 get 20 { 21 returnthis.UniqueID+":CardholderName"; 22 } 23 } 24 25 protectedoverridestringMonthListName 26 { 27 get 28 { 29 returnthis.UniqueID+":Month"; 30 } 31 } 32 33 protectedoverridestringYearListName 34 { 35 get 36 { 37 returnthis.UniqueID+":Year"; 38 } 39 }
这里以后,下面我们就只要实现IPostBackEventHandler接口,就可以调用我们的事件了,实现IPostBackEventHandler接口,其实只有一个方法。而且也很简单,代码:
1 2 3//大家看看我们只是将之前的事件通知代码移到了这里。 4voidIPostBackEventHandler.RaisePostBackEvent(stringargs) 5 { 6 ValidateCreditCardFormEventArgsve=newValidateCreditCardFormEventArgs( 7 PaymentMethodText,CreditCardNoText,CardholderNameText,ExpirationDateText); 8 9 OnValidateCreditCardForm(ve); 10 }
这样以后,我们的控件就可以引发服务器回传了,即,当你点击“提交”按钮时,我们的浏览器的状态栏下面就有刷新的进度条了。
注意,还有一个问题啊,我们确实能够使得我们的控件向服务器提交信息,但是服务器怎么来得到我们的提交的信息呢?
并不是我们把信息向服务器提交后,就什么都不管了,然后服务器就”很听话的“进行验证。不是这样的,起码我们还要告诉服务器,我们提交了哪些要被验证的信息。
那么服务器这样接受到我们的信息,,很简单,只要实现一个接口就可以了--IPostBackDataHandler。
接口有两个方法,第一个就是LoadPostData方法,就是来获取我们的信息,并且判断我们这次提交的信息和上次有变化没有。
上面的方法返回一个布尔的值,如果返回true,就自动的调用下一个方法RaisePostDataChangedEvent,大家可以根据方法的英文看到他们的作用。
这里我们只是讲下LoadPostData方法,方法的完成写法是这样的:
1boolLoadPostData(stringpostDataKey,NameValueCollectionvalues) 2{ 3 4}
看见方法不要害怕,方法的参数,前一个参数,我们不要管,只要看看后面的参数就可以了。
我们的信息的提交,都是在相应的输入框,下拉框中写好了,传给服务器的,其实是以:键值对,传了的.
键:就是我们输入框等的名字,name
值:就是输入的值。
其实NameValueCollection就是一个哈希表,来存放键值对的。
我们之前的所有输入的信息被包含成了一个NameValueCollection传到服务器,然后服务器就通过对应的“键”(name)来获取值,然后验证。
代码如下:
1 boolIPostBackDataHandler.LoadPostData(stringpostDataKey,NameValueCollectionvalues) 2 { 3 stringpaymentMethod=values[PaymentMethodListName]=="0"?"Master":"Visa"; 4 if(paymentMethod!=PaymentMethodText) 5 { 6 PaymentMethod=paymentMethod; 7 hasPaymentMethodChanged=true; 8 } 9 10 stringcreditCardNo=values[CreditCardNoTextName]; 11 if(creditCardNo!=CreditCardNoText) 12 { 13 CreditCardNoText=creditCardNo; 14 hasCreditCardNoChanged=true; 15 } 16 17 stringcardholderName=values[CardholderNameTextName]; 18 if(cardholderName!=CardholderNameText) 19 { 20 CardholderNameText=cardholderName; 21 hasCardholderNameChanged=true; 22 } 23 24 intmonth=int.Parse(values[MonthListName]); 25 intyear=int.Parse(values[YearListName]); 26 DateTimeexpirationDate=newDateTime(year,month,10); 27 if(expirationDate!=ExpirationDateText) 28 { 29 ExpirationDateText=expirationDate; 30 hasExpirationDateChanged=true; 31 } 32 33 34 if(!string.IsNullOrEmpty(values[SubmitButtonName])) 35 Page.RegisterRequiresRaiseEvent(this); 36 37 returnhasExpirationDateChanged|| 38 hasCreditCardNoChanged|| 39 hasPaymentMethodChanged|| 40 hasCardholderNameChanged; 41 42 }
这样,我们整个控件就写完了,不知道大家懂了没:有问题回复!完整代码如下:
1usingSystem; 2usingSystem.Collections.Generic; 3usingSystem.Text; 4usingSystem.Web; 5usingSystem.Web.UI; 6usingSystem.Web.UI.WebControls; 7usingSystem.Collections; 8 9usingSystem.Collections.Specialized; 10 11namespaceCreditCardForm 12{ 13 publicclassCreditCardForm6:CreditCardForm5,IPostBackEventHandler,IPostBackDataHandler 14 { 15 #regionoverridename 16 protectedoverridestringPaymentMethodListName 17 { 18 get 19 { 20 returnthis.UniqueID+":PaymentMethod"; 21 } 22 } 23 24 protectedoverridestringCreditCardNoTextName 25 { 26 get 27 { 28 returnthis.UniqueID+":CreditCardNo"; 29 } 30 } 31 32 protectedoverridestringCardholderNameTextName 33 { 34 get 35 { 36 returnthis.UniqueID+":CardholderName"; 37 } 38 } 39 40 protectedoverridestringMonthListName 41 { 42 get 43 { 44 returnthis.UniqueID+":Month"; 45 } 46 } 47 48 protectedoverridestringYearListName 49 { 50 get 51 { 52 returnthis.UniqueID+":Year"; 53 } 54 } 55 56 protectedoverridestringSubmitButtonName 57 { 58 get 59 { 60 returnthis.UniqueID; 61 } 62 } 63 #endregion 64 #regionprorerty 65 66 publicstringPaymentMethodText 67 { 68 get 69 { 70 returnViewState["PaymentMethod"]!=null?(string)ViewState["PaymentMethod"]:string.Empty; 71 } 72 set 73 { 74 ViewState["PaymentMethod"]=value; 75 } 76 } 77 78 79 publicstringCreditCardNoText 80 { 81 get 82 { 83 returnViewState["CreditCardNo"]!=null?(string)ViewState["CreditCardNo"]:string.Empty; 84 } 85 set 86 { 87 ViewState["CreditCardNo"]=value; 88 } 89 } 90 91 publicstringCardholderNameText 92 { 93 get 94 { 95 returnViewState["CardholderName"]!=null?(string)ViewState["CardholderName"]:string.Empty; 96 } 97 set 98 { 99 ViewState["CardholderName"]=value; 100 } 101 } 102 103 publicDateTimeExpirationDateText 104 { 105 get 106 { 107 returnViewState["ExpirationDate"]!=null?(DateTime)ViewState["ExpirationDate"]:DateTime.Now; 108 } 109 set 110 { 111 ViewState["ExpirationDate"]=value; 112 } 113 } 114 115 116 #endregion 117 118 #regionevents 119 privatestaticobjectValidateCreditCardFormKey=newobject(); 120 publiceventValidateCreditCardFormEventHandlerValidateCreditCardForm 121 { 122 add 123 { 124 Events.AddHandler(ValidateCreditCardFormKey,value); 125 } 126 remove 127 { 128 Events.RemoveHandler(ValidateCreditCardFormKey,value); 129 } 130 } 131 132 133 protectedvoidOnValidateCreditCardForm(ValidateCreditCardFormEventArgsargs) 134 { 135 ValidateCreditCardFormEventHandlerhandler=Events[ValidateCreditCardFormKey] 136 asValidateCreditCardFormEventHandler; 137 if(handler!=null) 138 handler(this,args); 139 } 140 141 #endregion 142 voidIPostBackEventHandler.RaisePostBackEvent(stringargs) 143 { 144 ValidateCreditCardFormEventArgsve=newValidateCreditCardFormEventArgs( 145 PaymentMethodText,CreditCardNoText,CardholderNameText,ExpirationDateText); 146 147 OnValidateCreditCardForm(ve); 148 } 149 150 privateboolhasPaymentMethodChanged; 151 privateboolhasCreditCardNoChanged; 152 privateboolhasCardholderNameChanged; 153 privateboolhasExpirationDateChanged; 154 155 boolIPostBackDataHandler.LoadPostData(stringpostDataKey,NameValueCollectionvalues) 156 { 157 stringpaymentMethod=values[PaymentMethodListName]=="0"?"Master":"Visa"; 158 if(paymentMethod!=PaymentMethodText) 159 { 160 PaymentMethod=paymentMethod; 161 hasPaymentMethodChanged=true; 162 } 163 164 stringcreditCardNo=values[CreditCardNoTextName]; 165 if(creditCardNo!=CreditCardNoText) 166 { 167 CreditCardNoText=creditCardNo; 168 hasCreditCardNoChanged=true; 169 } 170 171 stringcardholderName=values[CardholderNameTextName]; 172 if(cardholderName!=CardholderNameText) 173 { 174 CardholderNameText=cardholderName; 175 hasCardholderNameChanged=true; 176 } 177 178 intmonth=int.Parse(values[MonthListName]); 179 intyear=int.Parse(values[YearListName]); 180 DateTimeexpirationDate=newDateTime(year,month,10); 181 if(expirationDate!=ExpirationDateText) 182 { 183 ExpirationDateText=expirationDate; 184 hasExpirationDateChanged=true; 185 } 186 187 188 if(!string.IsNullOrEmpty(values[SubmitButtonName])) 189 Page.RegisterRequiresRaiseEvent(this); 190 191 returnhasExpirationDateChanged|| 192 hasCreditCardNoChanged|| 193 hasPaymentMethodChanged|| 194 hasCardholderNameChanged; 195 196 } 197 198 voidIPostBackDataHandler.RaisePostDataChangedEvent() 199 { 200 boolhasChanged; 201 hasChanged=hasCardholderNameChanged|| 202 hasCreditCardNoChanged|| 203 hasPaymentMethodChanged|| 204 hasExpirationDateChanged; 205 206 if(hasChanged) 207 { 208 209 ValidateCreditCardFormEventArgsargs=newValidateCreditCardFormEventArgs( 210 PaymentMethod,CreditCardNoText,CardholderNameText,ExpirationDateText); 211 212 OnValidateCreditCardForm(args); 213 } 214 } 215 216 } 217} 218
相关文章推荐
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
- ASP.NET 2.0服务器控件与组件开发高级编程:为自定义控件添加设计时属性
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
- ASP.NET自定义控件组件开发 第五章 模板控件开发
- ASP.NET组件与开发之复合控件的事件处理
- [ASP.NET开发系列]在用户控件中添加事件 -- 摘自 tigerwen01
- ASP.NET组件与开发之复合控件的事件处理
- ASP.NET自定义控件组件开发 第五章 模板控件开发
- [ASP.NET开发系列]在用户控件中添加事件
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl
- ★★★【庖丁解牛:纵向切入Asp.net 3.5控件和组件开发技术系列—(5)事件和数据回发机制】★★★
- ASP.NET3.5控件和组件开发:高效事件的处理
- ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl