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