第三章 爲控件添加事件 後篇
前一篇文章只是簡單的說了下事件,但是大家應該方法,在ASP.NET自定義控件中只是簡單那麼定義事件是行不
通。如果大家開發的是WinForm中的事件,之前的定義可能沒有什麼大的問題,只是在效率方法欠考慮而且,還是可以運行
的。
下面我們就回到ASP.NET中的事件。
大家也許看了我們之前定義的事件,確實,事件一般是那麼定義的,但是那樣定義事件後的,運行起來的效率不搞,
因爲那樣定義事件後,編譯器在編譯事件代碼的時候,會自動的爲我們加入很多多線程安全的代碼,就是說,雖然我們只是
定義幾行代碼,大但是編譯器爲我們做了很多額外的事情,當然,這樣代碼的運行的效率可想而知。
在很多的時候,我們自定義控件的事件不是需要考慮多線程安全等問題的,所我們就要改變代碼,使其運行的更加好,
我們就採用下面的方法:顯示的申明事件:
Code
1
2 //其實其實一個輔助的變量,用來做Hashtable中的”鍵“
3 private static object ValidateCreditCardFormKey = new object();
4 public event ValidateCreditCardFormEventHandler ValidateCreditCardForm
5 {
6 add
7 {
8 Events.AddHandler(ValidateCreditCardFormKey, value);
9 }
10 remove
11 {
12 Events.RemoveHandler(ValidateCreditCardFormKey, value);
13 }
14 }
15
16
17 protected void OnValidateCreditCardForm(ValidateCreditCardFormEventArgs args)
18 {
19 ValidateCreditCardFormEventHandler handler = Events[ValidateCreditCardFormKey]
20 as ValidateCreditCardFormEventHandler;
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的一些屬性:
Code
1 protected override string SubmitButtonName
2 {
3 get
4 {
5 return this.UniqueID ;
6 }
7 }
還有,每一次頁面提交給服務器後,解析頁面的this.UniqueID都不一樣。而且,如果在頁面中同時有兩個CreditCardForm,我們也要保證兩個控件的其他控件,如輸入框等等的name也不一樣,所以要分別重寫name。
Code
1 protected override string PaymentMethodListName
2 {
3 get
4 {
5 return this.UniqueID + ":PaymentMethod";
6 }
7 }
8
9 protected override string CreditCardNoTextName
10 {
11 get
12 {
13 return this.UniqueID + ":CreditCardNo";
14 }
15 }
16
17 protected override string CardholderNameTextName
18 {
19 get
20 {
21 return this.UniqueID + ":CardholderName";
22 }
23 }
24
25 protected override string MonthListName
26 {
27 get
28 {
29 return this.UniqueID +":Month";
30 }
31 }
32
33 protected override string YearListName
34 {
35 get
36 {
37 return this.UniqueID + ":Year";
38 }
39 }
這裏以後,下面我們就只要實現IPostBackEventHandler接口,就可以調用我們的事件了,實現IPostBackEventHandler接口,其實只有一個方法。而且也很簡單,代碼:
Code
1
2
3 //大家看看我們只是將之前的事件通知代碼移到了這裏。
4 void IPostBackEventHandler.RaisePostBackEvent(string args)
5 {
6 ValidateCreditCardFormEventArgs ve = new ValidateCreditCardFormEventArgs(
7 PaymentMethodText, CreditCardNoText, CardholderNameText, ExpirationDateText);
8
9 OnValidateCreditCardForm(ve);
10 }
這樣以後,我們的控件就可以引發服務器回傳了,即,當你點擊“提交”按鈕時,我們的瀏覽器的狀態欄下面就有刷新的
進度條了。
注意,還有一個問題啊,我們確實能夠使得我們的控件向服務器提交信息,但是服務器怎麼來得到我們的提交的信息
呢?
並不是我們把信息向服務器提交後,就什麼都不管了,然後服務器就”很聽話的“進行驗證。不是這樣的,起碼我們還要
告訴服務器,我們提交了哪些要被驗證的信息。
那麼服務器這樣接受到我們的信息,,很簡單,只要實現一個接口就可以了--IPostBackDataHandler。
接口有兩個方法,第一個就是LoadPostData方法,就是來獲取我們的信息,並且判斷我們這次提交的信息和上次有變化
沒有。
上面的方法返回一個布爾的值,如果返回true,就自動的調用下一個方法RaisePostDataChangedEvent,
大家可以根據方法的英文看到他們的作用。
這裏我們只是講下LoadPostData方法,方法的完成寫法是這樣的:
Code
1 bool LoadPostData(string postDataKey, NameValueCollection values)
2 {
3
4 }
看見方法不要害怕,方法的參數,前一個參數,我們不要管,只要看看後面的參數就可以了。
我們的信息的提交,都是在相應的輸入框,下拉框中寫好了,傳給服務器的,其實是以:鍵值對,傳了的.
鍵:就是我們輸入框等的名字,name
值:就是輸入的值。
其實NameValueCollection就是一個哈希表,來存放鍵值對的。
我們之前的所有輸入的信息被包含成了一個NameValueCollection傳到服務器,然後服務器就通過對應的“鍵”(name)來獲取值,然後驗證。
代碼如下:
Code
1 bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection values)
2 {
3 string paymentMethod = values[PaymentMethodListName] == "0" ? "Master" : "Visa";
4 if (paymentMethod != PaymentMethodText)
5 {
6 PaymentMethod = paymentMethod;
7 hasPaymentMethodChanged = true;
8 }
9
10 string creditCardNo = values[CreditCardNoTextName];
11 if (creditCardNo != CreditCardNoText)
12 {
13 CreditCardNoText = creditCardNo;
14 hasCreditCardNoChanged = true;
15 }
16
17 string cardholderName = values[CardholderNameTextName];
18 if (cardholderName != CardholderNameText)
19 {
20 CardholderNameText = cardholderName;
21 hasCardholderNameChanged = true;
22 }
23
24 int month = int.Parse(values[MonthListName]);
25 int year=int.Parse (values [YearListName ]);
26 DateTime expirationDate=new DateTime (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 return hasExpirationDateChanged||
38 hasCreditCardNoChanged ||
39 hasPaymentMethodChanged ||
40 hasCardholderNameChanged ;
41
42 }
這樣,我們整個控件就寫完了,不知道大家懂了沒:有問題回覆!完整代碼如下:
Code
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Web;
5 using System.Web.UI;
6 using System.Web.UI.WebControls;
7 using System.Collections ;
8
9 using System.Collections.Specialized ;
10
11 namespace CreditCardForm
12 {
13 public class CreditCardForm6:CreditCardForm5 ,IPostBackEventHandler,IPostBackDataHandler
14 {
15 #region override name
16 protected override string PaymentMethodListName
17 {
18 get
19 {
20 return this.UniqueID + ":PaymentMethod";
21 }
22 }
23
24 protected override string CreditCardNoTextName
25 {
26 get
27 {
28 return this.UniqueID + ":CreditCardNo";
29 }
30 }
31
32 protected override string CardholderNameTextName
33 {
34 get
35 {
36 return this.UniqueID + ":CardholderName";
37 }
38 }
39
40 protected override string MonthListName
41 {
42 get
43 {
44 return this.UniqueID +":Month";
45 }
46 }
47
48 protected override string YearListName
49 {
50 get
51 {
52 return this.UniqueID + ":Year";
53 }
54 }
55
56 protected override string SubmitButtonName
57 {
58 get
59 {
60 return this.UniqueID ;
61 }
62 }
63 #endregion
64 #region prorerty
65
66 public string PaymentMethodText
67 {
68 get
69 {
70 return ViewState["PaymentMethod"] != null ? (string)ViewState["PaymentMethod"] : string.Empty ;
71 }
72 set
73 {
74 ViewState["PaymentMethod"] = value;
75 }
76 }
77
78
79 public string CreditCardNoText
80 {
81 get
82 {
83 return ViewState["CreditCardNo"] != null ? (string)ViewState["CreditCardNo"] : string.Empty;
84 }
85 set
86 {
87 ViewState["CreditCardNo"] = value;
88 }
89 }
90
91 public string CardholderNameText
92 {
93 get
94 {
95 return ViewState["CardholderName"] != null ? (string)ViewState["CardholderName"] : string.Empty;
96 }
97 set
98 {
99 ViewState["CardholderName"] = value;
100 }
101 }
102
103 public DateTime ExpirationDateText
104 {
105 get
106 {
107 return ViewState["ExpirationDate"] != null ? (DateTime)ViewState["ExpirationDate"] : DateTime.Now;
108 }
109 set
110 {
111 ViewState["ExpirationDate"] = value;
112 }
113 }
114
115
116 #endregion
117
118 #region events
119 private static object ValidateCreditCardFormKey = new object();
120 public event ValidateCreditCardFormEventHandler ValidateCreditCardForm
121 {
122 add
123 {
124 Events.AddHandler(ValidateCreditCardFormKey, value);
125 }
126 remove
127 {
128 Events.RemoveHandler(ValidateCreditCardFormKey, value);
129 }
130 }
131
132
133 protected void OnValidateCreditCardForm(ValidateCreditCardFormEventArgs args)
134 {
135 ValidateCreditCardFormEventHandler handler = Events[ValidateCreditCardFormKey]
136 as ValidateCreditCardFormEventHandler;
137 if (handler != null)
138 handler(this, args);
139 }
140
141 #endregion
142 void IPostBackEventHandler.RaisePostBackEvent(string args)
143 {
144 ValidateCreditCardFormEventArgs ve = new ValidateCreditCardFormEventArgs(
145 PaymentMethodText, CreditCardNoText, CardholderNameText, ExpirationDateText);
146
147 OnValidateCreditCardForm(ve);
148 }
149
150 private bool hasPaymentMethodChanged;
151 private bool hasCreditCardNoChanged;
152 private bool hasCardholderNameChanged;
153 private bool hasExpirationDateChanged;
154
155 bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection values)
156 {
157 string paymentMethod = values[PaymentMethodListName] == "0" ? "Master" : "Visa";
158 if (paymentMethod != PaymentMethodText)
159 {
160 PaymentMethod = paymentMethod;
161 hasPaymentMethodChanged = true;
162 }
163
164 string creditCardNo = values[CreditCardNoTextName];
165 if (creditCardNo != CreditCardNoText)
166 {
167 CreditCardNoText = creditCardNo;
168 hasCreditCardNoChanged = true;
169 }
170
171 string cardholderName = values[CardholderNameTextName];
172 if (cardholderName != CardholderNameText)
173 {
174 CardholderNameText = cardholderName;
175 hasCardholderNameChanged = true;
176 }
177
178 int month = int.Parse(values[MonthListName]);
179 int year=int.Parse (values [YearListName ]);
180 DateTime expirationDate=new DateTime (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 return hasExpirationDateChanged||
192 hasCreditCardNoChanged ||
193 hasPaymentMethodChanged ||
194 hasCardholderNameChanged ;
195
196 }
197
198 void IPostBackDataHandler.RaisePostDataChangedEvent()
199 {
200 bool hasChanged;
201 hasChanged = hasCardholderNameChanged ||
202 hasCreditCardNoChanged ||
203 hasPaymentMethodChanged ||
204 hasExpirationDateChanged;
205
206 if (hasChanged)
207 {
208
209 ValidateCreditCardFormEventArgs args = new ValidateCreditCardFormEventArgs(
210 PaymentMethod, CreditCardNoText, CardholderNameText, ExpirationDateText);
211
212 OnValidateCreditCardForm(args);
213 }
214 }
215
216 }
217 }
218