ASP.NET進階:認清控制元件 之 Button (轉)
“做.NET不值錢,沒有技術含量,拖拖控制元件就行了。”———— 這類言語我最討厭了,一點技術含量都沒有,不懂.NET就瞎嚷嚷。不管做什麼,做好都不容易,你沒做過怎麼知道沒有技術含量呢? 我們既享受控制元件帶來的快捷,也知其原理,甚至可以自己開發控制元件,你還能說我們沒技術含量?!
控制元件是什麼? 是.NET Framework對Html裡的元素的封裝。 他把一個變成了 Button類,把變成了Label類,把變成了DropDownList。這就是控制元件,就是這些類。
上節我們提到了Page類,Page的生命週期裡有些事件是和處理控制元件類有關的。
PreInit
使用該事件來執行下列操作:
檢查 IsPostBack 屬性來確定是不是第一次處理該頁。
建立或重新建立動態控制元件。
動態設定主控頁。
動態設定 Theme 屬性。
讀取或設定配置檔案屬性值。
Render
這不是事件;在處理的這個階段,Page 物件會在每個控制元件上呼叫此方法。所有 ASP.NET Web 伺服器控制元件都有一個用於寫出傳送給瀏覽器的控制元件標記的 Render 方法。
如果建立自定義控制元件,通常要重寫此方法以輸出控制元件的標記。不過,如果自定義控制元件只合並標準的 ASP.NET Web 伺服器控制元件,不合並自定義標記,則不需要重寫 Render 方法。
一個是初始化,一個是顯示,其他的還有事件之類的,我們暫且不提。我們可以看出,初始化其實就是例項化desinger.cs裡用到的控制元件。而最終這些控制元件都需要轉換成HTML標籤,也就是被Page呼叫其Render方法。Page自身也是控制元件所,以Page的Render就是負責生成HTML的。
控制元件類都在System.Web.UI.WebControls下,我們可以開啟MSDN檢視一些常用控制元件的類和其相關的事件方法。如果有用Refletor的話,可以開啟System.Web.dll檢視更加詳細的原始碼。你會發現有意思的繼承關係,理解MS的設計理念,也更方便我們對控制元件有個更加清晰的認識。
Button類。
當我們在FORM裡放置一個Button,該按鈕預設為Submit按鈕,如果設為UseSubmitBehavior. = false,就可以看到客戶端會生成該按鈕需要的JS程式碼。
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> <div class="aspNetHidden">
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTcxODU4OTc0MWRk6Htqf5QF2exQx/BOtdDx1djNfbW7y3bPbmRizhypOr4=" />
div>
<script type="text/javascript">
//
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
//]]>
script>
<input type="submit" name="Button1" value="Button" id="Button1" />
<input type="button" name="Button2" value="Button" onclick="javascript.:__doPostBack('Button2','')" id="Button2" />
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTcxODU4OTc0MWRk6Htqf5QF2exQx/BOtdDx1djNfbW7y3bPbmRizhypOr4=" />
div>
<script type="text/javascript">
//
var theForm = document.forms['form1'];
if (!theForm) {
theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
//]]>
script>
<input type="submit" name="Button1" value="Button" id="Button1" />
<input type="button" name="Button2" value="Button" onclick="javascript.:__doPostBack('Button2','')" id="Button2" />
__doPostBack就是出發form的提交,而Button2呼叫的時候傳值了自己的名字,然後__EVENTTARGET的值被設為了Button2,這樣在提交的時候,Post的資料裡就會告訴服務端是Button2觸發的!再看Button1卻沒有呼叫__doPostBack,因為他是submit型別,在提交的時候瀏覽器會把他的名字預設提交過去,同時其他的按鈕不會被提交。
所以,既然服務端知道了是哪個按鈕被點過,自然就會呼叫該按鈕例項的OnClick方法。看看Page類裡有一個方法。
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->if (this.IsPostBack)
{
this.RaisePostBackEvent(this._requestValueCollection);
}
private void RaisePostBackEvent(NameValueCollection postData)
{
if (this._registeredControlThatRequireRaiseEvent != null)
{
this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent, null);
}
else
{
string str = postData["__EVENTTARGET"];
bool flag = !string.IsNullOrEmpty(str);
if (flag || (this.AutoPostBackControl != null))
{
Control control = null;
if (flag)
{
control = this.FindControl(str);
}
if ((control != null) && (control.PostBackEventHandler != null))
{
string eventArgument = postData["__EVENTARGUMENT"];
this.RaisePostBackEvent(control.PostBackEventHandler, eventArgument);
}
}
else
{
this.Validate();
}
}
}
{
this.RaisePostBackEvent(this._requestValueCollection);
}
private void RaisePostBackEvent(NameValueCollection postData)
{
if (this._registeredControlThatRequireRaiseEvent != null)
{
this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent, null);
}
else
{
string str = postData["__EVENTTARGET"];
bool flag = !string.IsNullOrEmpty(str);
if (flag || (this.AutoPostBackControl != null))
{
Control control = null;
if (flag)
{
control = this.FindControl(str);
}
if ((control != null) && (control.PostBackEventHandler != null))
{
string eventArgument = postData["__EVENTARGUMENT"];
this.RaisePostBackEvent(control.PostBackEventHandler, eventArgument);
}
}
else
{
this.Validate();
}
}
}
啊哈!明白沒有?在IsPostBack(也就是提交)後,呼叫了觸發所有控制元件事件的方法。postData["__EVENTTARGET"]明顯就是我們剛才的點的按鈕名稱,然後通過FindControl得到該物件,最後呼叫RaisePostBackEvent方法出發該物件的事件。再往下看具體流程:
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
{
sourceControl.RaisePostBackEvent(eventArgument);
}
protected virtual void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
{
sourceControl.RaisePostBackEvent(eventArgument);
}
也就是說,Button類必須實現IPostBackEventHandler介面(因為Page不知道控制元件到底是什麼,所以要使用介面,這就是介面的用處)。
看看具體實現:
<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> protected virtual void RaisePostBackEvent(string eventArgument)
{
base.ValidateEvent(this.UniqueID, eventArgument);
if (this.CausesValidation)
{
this.Page.Validate(this.ValidationGroup);
}
this.OnClick(EventArgs.Empty);
this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}
{
base.ValidateEvent(this.UniqueID, eventArgument);
if (this.CausesValidation)
{
this.Page.Validate(this.ValidationGroup);
}
this.OnClick(EventArgs.Empty);
this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}
首先是驗證,然後是執行OnClick,然後執行OnCommand。呵呵,一個OnClick我們終於走完了~ 感覺如何? 頭漲了沒?
看下Button類,確實繼承IPostBackEventHandler介面。
<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> [Designer("System.Web.UI.Design.WebControls.ButtonDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), SupportsEventValidation, ToolboxData(""server\" Text=\"Button\">{0}:Button>"), DefaultEvent("Click"), DefaultProperty("Text"), DataBindingHandler("System.Web.UI.Design.TextDataBindingHandler, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public class Button : WebControl, IButtonControl, IPostBackEventHandler
{
....
[WebCategory("Action"), WebSysDescription("Button_OnClick")]
public event EventHandler Click;
protected virtual void OnClick(EventArgs e)
[WebCategory("Action"), WebSysDescription("Button_OnCommand")]
public event CommandEventHandler Command;
[WebSysDescription("Button_Text"), WebCategory("Appearance"), Bindable(true), Localizable(true), DefaultValue("")]
public string Text { get; set; }
....
}
public class Button : WebControl, IButtonControl, IPostBackEventHandler
{
....
[WebCategory("Action"), WebSysDescription("Button_OnClick")]
public event EventHandler Click;
protected virtual void OnClick(EventArgs e)
[WebCategory("Action"), WebSysDescription("Button_OnCommand")]
public event CommandEventHandler Command;
[WebSysDescription("Button_Text"), WebCategory("Appearance"), Bindable(true), Localizable(true), DefaultValue("")]
public string Text { get; set; }
....
}
並且看到熟悉的Click,Command,Text,而ID,Width,Height則在他的父類中。
看看OnClick是幹嘛的?
<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler) base.Events[EventClick];
if (handler != null)
{
handler(this, e);
}
}
{
EventHandler handler = (EventHandler) base.Events[EventClick];
if (handler != null)
{
handler(this, e);
}
}
OnClick的方法是被點選後執行的方法,具體是從Events裡找到EventClick型別的委託,其實就是判斷Click事件是否被訂閱,如果有該型別委託,則表明已經被訂閱,便執行該委託例項(也就是我們定義的Click具體方法)。
再來看下是如何訂閱的:
<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> [WebCategory("Action"), WebSysDescription("Button_OnClick")]
public event EventHandler Click
{
add
{
base.Events.AddHandler(EventClick, value);
}
remove
{
base.Events.RemoveHandler(EventClick, value);
}
}
public event EventHandler Click
{
add
{
base.Events.AddHandler(EventClick, value);
}
remove
{
base.Events.RemoveHandler(EventClick, value);
}
}
Click事件具有add和remove兩個類似屬性的get和set的方法,這當然是C#的特定語法,實際編譯後的IL裡是兩個小方法。
Add是訂閱,remove是取消訂閱。AddHandler就是把具體的方法和委託型別新增到Events裡。
<!--Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> public void AddHandler(object key, Delegate value)
{
ListEntry entry = this.Find(key);
if (entry != null)
{
entry.handler = Delegate.Combine(entry.handler, value);
}
else
{
this.head = new ListEntry(key, value, this.head);
}
}
{
ListEntry entry = this.Find(key);
if (entry != null)
{
entry.handler = Delegate.Combine(entry.handler, value);
}
else
{
this.head = new ListEntry(key, value, this.head);
}
}
一氣呵成,我們知道了Click的具體呼叫實現,且明白的事件的訂閱。後面再說控制元件的其他屬性,休息休息。後面會介紹Render和DataBind :)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-676022/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- ASP.NET Web Forms – Button 控制元件簡介ASP.NETWebORM控制元件
- MFC控制元件之Button基本用法控制元件
- asp.net 給button 控制元件 換個背景圖片ASP.NET控制元件
- tkinter學習系列(四)之Button 控制元件控制元件
- Asp.Net MVC 系列--進階篇之FilterASP.NETMVCFilter
- android:Button控制元件Android控制元件
- Asp.Net MVC4系列--進階篇之AJAXASP.NETMVC
- Asp.Net MVC4 系列--進階篇之ViewASP.NETMVCView
- 【2024-06-06】認清上進
- Asp.Net MVC4 系列--進階篇之Model(1)ASP.NETMVC
- Asp.Net MVC4 系列--進階篇之Model(2)ASP.NETMVC
- Asp.Net MVC系列--進階篇之controller(1)ASP.NETMVCController
- Asp.Net MVC4系列--進階篇之Helper(1)ASP.NETMVC
- Asp.Net MVC4 系列--進階篇之Helper(2)ASP.NETMVC
- 認證系統之登入認證系統的進階使用 (二)
- asp.net高階教程 (轉)ASP.NET
- ASP.NET - Button、LinkButton和ImageButtonASP.NET
- iOS進階之訊息轉發機制iOS
- 技術進階的書籍清單之一
- Asp.Net MVC4 系列--進階篇之Controller(2)ASP.NETMVCController
- tkinter中button按鈕控制元件(三)控制元件
- asp.net高階教程(續) (轉)ASP.NET
- Android UI控制元件系列:Button(按鈕)AndroidUI控制元件
- 建立ASP.NET WEB自定義控制元件(轉)ASP.NETWeb控制元件
- ASP.NET驗證控制元件祥解 (轉)ASP.NET控制元件
- 自定義asp.net控制元件分析 (一) (轉)ASP.NET控制元件
- 自定義asp.net控制元件分析(二) (轉)ASP.NET控制元件
- Django 進階之 celeryDjango
- javascript 進階之 - PromiseJavaScriptPromise
- IOS 進階之 WKWebViewiOSWebView
- 前端進階之困前端
- C1 能力認證——Web進階Web
- Pytest高階進階之Fixture
- 人智化轉型 華為雲微認證帶你實力進階
- Go gRPC進階-TLS認證+自定義方法認證(七)GoRPCTLS
- 高階前端的進階——CSS之flex前端CSSFlex
- JavaScript進階之繼承JavaScript繼承
- JavaScript進階之原型鏈JavaScript原型