定制AjaxControlToolkit:给CalendarExtender增加清除功能
其實像AutoCompleteExtender之類的其它擴展也是與此類似,這里只是用CalendarExtender舉例子了。
AjaxControlToolkit確實是個好東西,但是我實在不明白設計者是出于什么目的一定要把它捆在某一個文本框上,使得這組控件變得很難用。對日期控件來說,可能很多人用過梅花雨做的那個日期控件,那個控件確實很好用,而且其setday(this)這樣的調用方式也非常簡單明了,但是它存在許多問題(跟主題無關,不再細說),為了說服我的同事轉用CalendarExtender,我決定想個辦法使CalendarExtender也能像梅花雨日期控件一樣簡單好用。
由于AjaxControlToolkit天生的設計,不修改AjaxControlToolkit.dll是絕不可能達到目的的,不過好在微軟提供了源代碼(不知道應該說感謝微軟,還是應該說感謝多年來堅持呼吁開源的人士- -!),所以修改dll變得一點也不復雜了。
首先,在結構上CalendarBehavior類繼承自BehaviorBase類, BehaviorBase又繼承自Sys.UI.Behavior類,這幾個類中,CalendarBehavior和BehaviorBase類存在于AjaxControlToolkit項目中,可以直接修改,但是Sys.UI.Behavior存在于.NET Framework附帶的System.Web.Extension.dll中,所以修改只能止于BehaviorBase了,要修改Sys.UI.Behavior的話,代價太大,不考慮。
但是,偏偏把擴展綁定到一個固定的控件上這個規則,就是Sys.UI.Behavior定義的!在這個類的構造函數中,把目標文本框傳入,此后只能從子類調用繼承的方法get_element()來獲取這個文本框,而無法去更改它,因為沒有基類Sys.UI.Behavior的實例,所以訪問它的私有屬性自然也是不可能的事。本來,如果給基類增加一個set_element()方法,既簡單效率又最高,但是偏偏這個最佳途徑被堵死了。于是只能退而求其次,從CalendarBehavior類身上做文章。
為了使目標文本框可以動態地變化,首先給CalendarBehavior類增加一個私有屬性:
this._element?=?element;
然后要有讀取它的公共方法:
get_targetElement:?function()?{????????returnthis._element;
}
把CalendarBehavior類中所有的get_element()方法替換成get_targetElement()方法,就使得Sys.UI.Behavior沒有用武之地了,現在只要再有一個改變_element私有屬性的方法即可大功靠成。
但是這個set方法并不是這么簡單。首先,在構造CalendarExtender的時候,向目標文本框附加了好幾個事件,現在既然要換文本框,原來的宿主文本框上綁定的事件必須被解除,并且把它們附加到新的文本框上;其次,CalendarBehavior有一個_popupBehavior私有屬性,它是一個PopupExtender類的一個實例,PopupBehavior類實現了彈出div,定位擴展控件等功能,包括AutoCompleteExtender等其它彈出式控件都使用這個類的功能。CalendarBehavior在構造的時候,_popupBehavior也被按照第一個文本框的參數進行了構造,現在雖然目標文本框換了,但是_popupBehavior仍然是相對于第一個文本框而言的,需要將這個對象按照新的目標文本框重新構建;與_popupBehavior類似的還包括其它幾個私有屬性,set方法的代碼如下:
set_targetElement:?function(element)?{????????///?<summary>
///?switch?target?textbox
///?</summary>
if(this._element.id?==element.id)
????????????return;
????????$common.removeHandlers(this.get_targetElement(),?this._element$delegates);
????????$addHandlers(element,?this._element$delegates);
????????this._element?=element;
????????this._textbox?=AjaxControlToolkit.TextBoxWrapper.get_Wrapper(element);
????????if(this._popupBehavior)?{
????????????this._popupBehavior.dispose();
????????????this._popupBehavior?=null;
????????}
????????if(this._container)?{
????????????if(this._container.parentNode)?{?//added?this?check?before?calling?removeChild?WI:?8486
this._container.parentNode.removeChild(this._container);
????????????}
????????????this._container?=null;
????????}
????????if(this._popupDiv)?{
????????????$common.removeHandlers(this._popupDiv,?this._popup$delegates);
????????????this._popupDiv?=null;
????????}
????},
其中,第一句先判斷要設置的目標控件是不是與當前控件一樣,是非常重要的一步,否則會造成無謂的效率浪費,而且這一比較幾乎不需要什么代價。
經過這樣的包裝后,項目中就可以調用set_targetElement()方法進行動態切換目標文本框了,因為我們的項目使用母版頁,所以我在母版頁中增加了這樣一個
函數:
functionsetday(element)?{????varce?=$find("pm_ce1");
????ce.set_targetElement(element);
????ce.show();
}
其中,pm_ce1是ajaxToolkit:CalendarExtender的BehaviorID,我在母版頁中直接放了一個CalendarExtender,這樣內容頁就可以完全忽略CalendarExtender的細節,像調用梅花雨日期控件一樣了:
<asp:TextBox?ID="txt1"runat="server"onclick="setday(this);"></asp:TextBox>?
順便貼一個CalendarExtender的樣式,這是從一個國外的網站上抄來的,忘了是哪個網站了,估計作者也看不懂中文,不至于來罵我一頓。:)
.cal_Theme1?.ajax__calendar_container{
????background-color:#e2e2e2;
????border:solid?1px?#cccccc;
}
.cal_Theme1?.ajax__calendar_header
{
????background-color:#ffffff;
????margin-bottom:4px;
}
.cal_Theme1?.ajax__calendar_title,?.cal_Theme1?.ajax__calendar_next,?.cal_Theme1?.ajax__calendar_prev
{
????color:#004080;
????padding-top:3px;
}
.cal_Theme1?.ajax__calendar_body
{
????background-color:#e9e9e9;
????border:solid?1px?#cccccc;
}
.cal_Theme1?.ajax__calendar_dayname
{
????text-align:?center;
????font-weight:?bold;
????margin-bottom:?4px;
????margin-top:?2px;
}
.cal_Theme1?.ajax__calendar_day
{
????text-align:center;
}
.cal_Theme1?.ajax__calendar_hover?.ajax__calendar_day,?.cal_Theme1?.ajax__calendar_hover?.ajax__calendar_month,?.cal_Theme1?.ajax__calendar_hover?.ajax__calendar_year,?.cal_Theme1?.ajax__calendar_active
{
????color:#004080;
????font-weight:bold;
????background-color:#ffffff;
}
.cal_Theme1?.ajax__calendar_today
{
????font-weight:bold;
}
.cal_Theme1?.ajax__calendar_other,?.cal_Theme1?.ajax__calendar_hover?.ajax__calendar_today,?.cal_Theme1?.ajax__calendar_hover?.ajax__calendar_title
{
????color:#bbbbbb;
}
?
?指定CalendarExtender的CssClass屬性等于cal_Theme1即可。
這個主題運行時的截圖:
的最后,為了展示主題,我貼了一張截圖,也許大家注意到了,我的截圖的右下角有一個“清除”按鈕,這就是本文要介紹的更改。
在我們的項目中,大多數的錄入日期的文本框是不允許用戶手輸的,只能通過點擊--彈出日期選擇框的方式選擇,這樣可以避免煩人的檢查動作,當然也可以用MaskedEdit過濾,不過感覺沒必要,有日期控件了,就不弄那么復雜了,另外,項目中大部分代碼是以前寫的,當時沒有MaskedEdit可用,一直以來使用只讀的辦法來限制日期文本框。
由于文本框只讀,所以只要用戶一旦選擇了某個日期,就沒辦法使這個文本框變空了,大多數情況下,這并不是問題,但是在少數頁面,這一點相當煩人,更重要的是,以前的控件有這個功能,用戶已經習慣了這樣操作,現在突然告訴用戶你沒辦法清空它,這不怎么有說服力。而且從系統設計的角度講,那個文本框本來就是允許為空的,而且默認就是空的,后來選擇了日期以后,就再也沒辦法使它恢復到空值狀態,也不怎么說得過去。
因此我覺得有必要給CalendarExtender增加清除功能,使它能夠清空目標文本框。
清空的動作倒是非常簡單,但是要把它正確地顯示出來比較棘手。首先,要了解CalendarBehavior類的展示方法:首先有一個_popupDiv屬性,它是整個控件的載體,其它的控件都附加在這個div之上;而底部顯示“今天”的部分,是直接附加在總載體_popupDiv上的,因為本來底部只有它一個控件,它當然可以這樣做,但是現在要在它右側增加一個按鈕,就要改變一下這種行為: 增加一個_footer層作為底部控件的載體, 把今天日期作為子控件附加到_footer上面, 再增加一個_clearButton控件, 也附加到_footer上面. 實現這一流程的代碼如下:
1. 增加私有屬性:
this._clearButton?=null;this._footer?=null;
2. 在_buildFooter方法中, 改寫_today的展示方式:
_buildFooter:?function()?{????????///?<summary>
///?Builds?the?footer?for?the?calendar
///?</summary>
this._footer?=$common.createElementFromTemplate({
????????????nodeName:?"div",
????????????properties:?{?id:?this.get_id()?+"_footer"},
????????????cssClasses:?["ajax__calendar_footer"]
????????},?this._popupDiv);
????????vartodayWrapper?=$common.createElementFromTemplate({?nodeName:?"div"},?this._footer);
????????this._today?=$common.createElementFromTemplate({
????????????nodeName:?"div",
????????????properties:?{
????????????????id:?this.get_id()?+"_today",
????????????????mode:?"today"
????????????},
????????????events:?this._cell$delegates,
????????????//cssClasses:?["ajax__calendar_footer",?"ajax__calendar_today"]
cssClasses:?["ajax__calendar_today"]
????????},?todayWrapper);
????????varclearWrapper?=$common.createElementFromTemplate({?nodeName:?"div"},?this._footer);
????????this._clearButton?=$common.createElementFromTemplate({
????????????nodeName:?"div",
????????????properties:?{
????????????????id:?this.get_id()?+"_clearButton",
????????????????mode:?"clear"
????????????},
????????????events:?this._cell$delegates,
????????????cssClasses:?["ajax__calendar_clear"]
????????},?clearWrapper);
????},
這里我給它指定了一個新的css屬性ajax__calendar_clear, 允許用戶任意定義這個按鈕的樣式. 并且將它的事件也綁定到統一的_cell$delegates中, 為此要給_cell_onclick方法增加一個處理器:
case"clear":????this.get_targetElement().value?="";
????this._blur.post(true);
????this.raiseDateSelectionChanged();
????break;
進行到這里, 最重要的外觀"清除" 兩個字還沒看到, 所以顯然工作還沒有完成: 然后在_performLayout方法中把清除這兩個字附加上去:
if(!this._clearButton.firstChild)?{????????????this._clearButton.appendChild(document.createTextNode("\u6E05\u9664"));
????????}
這里我用了\u的方法表示漢字, 因為如果直接寫漢字的話, 至少在我的環境中看來是亂碼, 所以要直接用unicode碼表示. 另外, 我順便把today和最上方顯示年月的地方的顯示格式改了改, 默認的先月后年的顯示方法實在不符合中國人的習慣. 這兩個顯示格式都在_performLayout方法中.
最后在dispose方法中, 把清除按鈕清理掉:
if(this._clearButton)?{????????????$common.removeHandlers(this._clearButton,?this._cell$delegates);
????????????this._clearButton?=null;
????????}
這就差不多算是大功告成了, 除了底部顯示了兩行, 比較丑以外......
顯示兩行顯然是不能接受的, 所以打開Calendar.css , 繼續修改.?
因為要把今天的日期和清除按鈕放在同一行, 所以先修改.ajax__calendar_today和.ajax__calendar_footer:
.ajax__calendar_today?{cursor:pointer;padding-top:3px;float:left;}
然后增加一個ajax__calendar_clear類:
ajax__calendar_clear{
????font-weight:bold;
????color:Blue;
????text-decoration:underline;
????cursor:pointer;
????float:right;
????padding-top:3px;
}
現在就真的大功告成了.
轉載于:https://www.cnblogs.com/freedom831215/archive/2011/01/05/1926320.html
總結
以上是生活随笔為你收集整理的定制AjaxControlToolkit:给CalendarExtender增加清除功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【牢骚】360,你怎么对待别人,别人就怎
- 下一篇: mkfs的使用