詳解ASP.NET自定義控件開發實例
本文通過實現一個服務端控件來講解一下控件開發,該控件的功能如下:
1.顯示服務端時間,并不停更新
2.通過手動點擊刷新按鈕以AJAX獲取服務端***時間
3.能拖動
4.能記住在頁面上的位置,頁面回傳后位置不變
5.能配置一個定時時間,一到這個時間,自動回傳觸發用戶自定義的事件,
首先新建一個類庫項目HampWebControl,再新建一個類叫TipTime1,繼承WebControl類。如果不是從已有控件中繼承,一般就繼承WebControl類,它是所有ASP.NET服務端控件的基類。
我們編譯這個項目,再新建一個網站項目,引用HampWebControl項目,新建頁面,在工具箱中拖一個TipTime1控件到頁面上。
我們運行該頁面,就會發現HTML代碼如下:
就是說默認是呈現成一個span標簽,可以通過重載WebControl基類的TagKey屬性來改變。
這樣呈現在頁面上就是個DIV。 HtmlTextWriterTag是個枚舉,包含了很多HTML標簽。
WebControl基類的Render用來呈現內容,重載它便可以往頁面上呈現任何自定義的標簽。
這樣在頁面上就顯示了一個a標簽,如下圖所示:
注意看,這時a標簽是在DIV外面,如何將它放到DIV里面呢?這就要重載WebControl基類的RenderContents方法
這樣這個a標簽就在div里面了,如下圖所示:
接下來為最外圍的DIV加一些樣式,重載基類的AddAttributesToRender方法
這里有兩種寫法,利用HtmlTextWriterStyle枚舉或者直接寫CSS屬性名。
到這里大家了解了自定義控件如何呈現在頁面上。我們再新建一個類TipTime2,把依舊重載TagKey為DIV,然后重載RenderContents,顯示一個span標簽與一個input標簽。
這樣頁面上顯示了當前服務端的時間與一個按鈕,如圖所示:
接下來我們來讓用戶可以配置按鈕上的文字,為類TipTime2增加一個Text屬性:
同時將呈現按鈕的代碼改成:
這樣Text屬性便出現在設計視圖的屬性窗口。
修改Text的值,頁面上按鈕上的文本也跟著變了。注意Text屬性是存儲在ViewState中,這樣保證了回發后值不會丟失。
現在的問題是時間不會變,我們得用javascript來改變它的值。新建一個JS文件TipTime2.js。
這里先要說明的是,項目中已有一個JS文件__WebControlBase.js,里面是一些公用的JS方法,比如綁定事件、獲取控件坐標等,所有的方法都是
該方法的擴展方法:var HampWebControl=function(){ }
- //停止事件冒泡
- HampWebControl.prototype.StopBubble = function(e) {
- if (e && e.stopPropagation) { e.stopPropagation();
- } else
- {
- window.event.cancelBubble = true;
- }
- }
這樣可以減少全局變量,盡可能避免與其它js代碼的變量重名。我將每個控件作為HampWebControl方法的一個擴展方法存在,同時每個控件對
應一個數組,用以存儲頁面上所有該控件的js對象。每個控件對應一個Refresh方法,用以重新綁定事件,這是為了解決回傳后的問題。
現在控件呈現成HTML的結構是<div><span/><input/></div>,有3個標簽,我們需要用3個變量來分別存儲它們的DOM對象,方便以后操作。
后臺對HTML標簽命名時以當前控件的ClientID開頭,后面根據需要加后綴,這樣可以一定程度上防止標簽重名。由后臺將控件的ClientID傳過來,這樣便可以獲取所有DOM對象。拖動效果利用的是現成js方法,屬于純javascript效果,這里就不展開討論了,有興趣的童鞋可以查看示例項目源碼。
該方法是由后臺注冊腳本來調用的,如果在數組中已存在就取該對象,否則重新new一個。并調用初始化與綁定事件方法。
這時需要在后臺注冊該js文件才行。關鍵的操作時將該文件的“生成操作”屬性設置為“嵌入的資源”,使得編譯的時候該js文件會作為DLL文件的一部分。
接下來需要聲明所需的資源文件,嚴格按文件夾的結構來命名。這里注冊了2個JS文件:公用JS文件__WebControlBase.js與控件專用的JS文件TipTime2.js。
然后在代碼中注冊腳本即可。
在《道不遠人 深入解析ASP.NET2.0控件開發》這本書中,注冊腳本文件的代碼是放在OnPreRender方法中,但是實際應用中我發現,如果將自定義控件放在UpdatePanel控件中,就會引發一些問題,所以我都放在OnLoad方法中去注冊腳本文件。
注意注冊腳本文件這里用了2種不同的方法。
第1種是循環Head標簽里面是否存在了腳本,如果不存在,就插入一個<script>標簽。
第2種直接調用.NET的注冊方法。
- /// <summary>
- /// 向頁面注冊公共jacascript文件
- /// </summary>
- /// <param name="control">控件對象</param>
- internal static void RegisterCommonJSFile(Control control)
- {
- //注冊jacascript文件
- String jslink = "<script src='" +
- control.Page.ClientScript.GetWebResourceUrl(control.GetType(),
- "HampWebControl.includes.__WebControlBase.js")
- + "' type='text/javascript' ></script>";
- Register(jslink,control);
- }
- /// <summary>
- /// 注冊資源
- /// </summary>
- /// <param name="strLink">資源字符串</param>
- private static void Register(string strLink, Control control)
- {
- //為了保證資源只注冊一次,循環比較,已存在了就不添加
- Boolean flag = false;
- for (Int32 i = 0; i < control.Page.Header.Controls.Count; i++)
- {
- LiteralControl lc = control.Page.Header.Controls[i]
- as LiteralControl;
- if (lc != null)
- {
- if (lc.Text == strLink)
- {
- flag = true;
- break;
- }
- }
- }
- if (!flag)
- {
- LiteralControl include = new LiteralControl(strLink);
- control.Page.Header.Controls.Add(include);
- } }
第1種是用于注冊公用的資源文件,第2種用于注冊該控件特有的資源文件。 因為第2種方法只能保證多個該控件對象只注冊一個腳本,但不能保證其它控件也
重復注冊了該腳本,所以為了保證公用的資源文件只注冊一次,就用第1種方式。
下一步就是注冊要執行的腳本代碼:
這里如果控件是隱藏的,就不注冊。其實如果控件時放在其它容器控件中,比如Panel,而父容器控件設置為隱藏,那么該控件也不可見,但是依舊執行了注冊上面的腳本的代碼,所以要在前臺Init方法中去判斷相應的DOM對象是否存在,這里就沒有多做判斷。
***設置一下樣式,使之變為浮動,則控件在頁面上便能拖動了。
先講到這里,歸納一下,主要講了如何呈現自定義控件,如何添加屬性,如何增加資源文件。
原文鏈接:http://www.cnblogs.com/jintianhu/archive/2011/04/15/2017402.html
【編輯推薦】