1. 引言
我們經常會在網頁上看到使用星形圖案表示對某個軟體或某篇文章的評價,通常以五個星形作為最高標準,指定的等級對應使用實心填充,1-1所示,在學習ASP.NET自訂控制項的第一天,我們將開發這樣的自訂控制項。
2. 分析
可以看到這樣的一個自訂控制項包含兩部分:顯示的文本和包含兩種圖案(實心和空心星形)的圖片,為了呈現出這樣的結果,最方便的就是將這兩部分放到包含一行兩列的表格中。接下來要考慮的就是如何根據評分顯示若干實心和空心星形。
看到這個圖案的第一個想法可能就是根據評分首先顯示實心圖形,再判斷還需要顯示幾個空心星形(用5減評分),這樣的話需要做多次迴圈才能實現,但是在HTML裡有更好的實現方法。
想一下在使用CSS設定背景圖片時可以設定background-repeat屬性,該屬性標識背景圖片按哪個方向重複,可以利用這個特性首先顯示一個外層的div,該div始終顯示5個空心的星形圖形,在該層中嵌套另一個div,內層div顯示實心星形圖案。
|
background-repeat、background-image、background-color、background-position構成了設定背景樣式的屬性族 |
既然可以按X方向重複星形背景,那麼顯示指定個數的星形也就有答案了—我們可以根據得分設定指定層(div)的寬度即可,而且為了方便,將兩個星形圖案放置到一個圖片檔案裡,再應用background-position顯示指定位置星形即可。
根據以上分析,此自訂控制項中需要具有兩個屬性:
屬性 |
描述 |
Comment |
評分項目注釋,字串類型 |
Score |
得分,根據該屬性顯示相應的實心圖形,數字類型 |
3. 實現
1. 首先建立解決方案,包含ControlLibrary類庫(定義了自訂控制項類)和Web網站。
2. 在類庫中建立Image目錄,並放置使用的星形圖片stars.gif,為了能夠在網站中引用程式集中的資源檔,需要將圖片的Build Action(產生動作)屬性設定為Embedded Resource(嵌入資源),並且在AssemblyInfo.cs中聲明要使用的資源檔,如下所示:
[assembly: WebResource("ControlLibrary.Image.stars.gif","image/jpg")]
使用了WebResource(實際上是WebResourceAttribute類,為了使用該類需要引入System.Web.UI命名空間)定義了使用的資源,該類的建構函式使用了兩個參數,第一個參數是Web資源的名稱,第二個參數是MIME類型。Web資源的名稱必須遵循特定規則:命名空間名稱+目錄名稱+檔案名稱,中間用半形點字元分隔。MIME類型對於不同的檔案有不同的表示,詳細的MIME列表可參考相關資料。
|
資源的名稱可以通過.NET Reflector之類的工具瀏覽。載入某個程式集後,如果嵌有資源檔,可以通過Resources瀏覽目錄內嵌資源 |
3. 在類庫中建立自訂控制項類Star.cs,並引入必須的命名空間:
using System;using System.ComponentModel;using System.Web.UI;using System.Web.UI.WebControls;namespace ControlLibrary{ public class Star : WebControl { }}
4. 接下來定義Score和Comment屬性,將這兩個屬性儲存區在ViewState中,同時如果使用者沒有設計得分的情況下將得分設定為0,也就是將得分的預設值設定為0,這裡使用到了DefaultValutAttribute類,該類用於設定屬性的預設值。
[DefaultValue(0)]public int Score{ get { object obj = ViewState["Score"]; return obj == null ? 0 : Convert.ToInt32(obj); } set { ViewState["Score"] = value; }}public string Comment{ get { object obj = ViewState["Comment"]; return obj == null ? string.Empty : Convert.ToString(obj); } set { ViewState["Comment"] = value; }}
|
由於HTTP請求完成之後會中斷連線,把屬性儲存到私人變數中不會滿足我們的要求(提交回傳時會重建自訂控制項類,有可能丟失屬性值),所以儲存到ViewState中,回傳時能夠正確恢複屬性值 |
5. 重寫CreateChildControls方法,該類在Control類上定義,此方法用於建立控制項層次,以便為回傳和呈現做準備。在該方法中調用了自訂CreateControlHierarchy方法以建立控制項層次:
protected override void CreateChildControls(){ base.CreateChildControls(); CreateControlHierarchy();}
6. 在CreateControlHierarchy方法中建立一個一行兩列的表格,並分別調用CreateComment方法和CreateStarts方法建立注釋和星形圖按:
protected virtual void CreateControlHierarchy(){ Table table = new Table(); TableRow row = new TableRow(); table.Rows.Add(row); TableCell comment = new TableCell(); CreateComment(comment); row.Cells.Add(comment); TableCell stars = new TableCell(); CreateStars(stars); row.Cells.Add(stars); this.Controls.Add(table);}
7. 實現CreateComment方法,該方法接收一個TableCell參數當做顯示文本的容器,直接設定儲存格的文本為注釋字串:
private void CreateComment(TableCell cell){ cell.Text = Comment;}
8. 實現CreateStarts方法,該方法亦接收一個TableCell當做參數,首先取得圖片資源檔的路徑,並在儲存格裡建立嵌套的層(在伺服器端控制項中Panel類與div相對應)並根據得分設設定其相應屬性:
private void CreateStars(TableCell cell){ string starPath = Page.ClientScript.GetWebResourceUrl(this.GetType(), "ControlLibrary.Image.stars.gif"); Panel panBg = new Panel(); panBg.Style.Add(HtmlTextWriterStyle.Width, "80px"); panBg.Style.Add(HtmlTextWriterStyle.Height, "16px"); panBg.Style.Add(HtmlTextWriterStyle.TextAlign, "left"); panBg.Style.Add(HtmlTextWriterStyle.Overflow, "hidden"); panBg.Style.Add(HtmlTextWriterStyle.BackgroundImage, starPath); panBg.Style.Add("background-position", "0px -32px"); panBg.Style.Add("background-repeat", "repeat-x"); cell.Controls.Add(panBg); Panel panCur = new Panel(); string width=Score*16+"px"; panCur.Style.Add(HtmlTextWriterStyle.Width, width); panCur.Style.Add(HtmlTextWriterStyle.Height, "16px"); panCur.Style.Add(HtmlTextWriterStyle.BackgroundImage, starPath); panCur.Style.Add("background-position", "0px 0px"); panCur.Style.Add("background-repeat", "repeat-x"); panBg.Controls.Add(panCur);}
9. 重寫父類的Render方法,在該方法中將伺服器控制項的內容傳遞給HtmlTextWriter對象以在用戶端轉譯內容,在該方法中調用了PrepareControlForRender方法:
protected override void Render(HtmlTextWriter writer){ PrepareControlForReader(); base.Render(writer);}
10. 實現PrepareControlForRender方法,該方法用於在呈現前進行其他樣式的設定,在本控制項中,只是簡單的設定了表格的CellSpacing和CellPadding屬性:
private void PrepareControlForReader(){ if (this.Controls.Count < 1) return; Table table = (Table)this.Controls[0]; table.CellSpacing = 0; table.CellPadding = 0;}
11. 在網站中添加ControlLibrary類庫的引用,並在Default.aspx頁面中加入自訂控制項的聲明:
<%@ Register Assembly="ControlLibrary" Namespace="ControlLibrary" TagPrefix="cc" %>
12. 在頁面相應位置定義自訂控制項:
<%@ Register Assembly=?ControlLibrary? Namespace=?ControlLibrary? TagPrefix=?cc? %>
13. 預覽效果。
|
在多個頁面使用自訂控制項在每一個頁均需要加入聲明,有一個更好的替代方法是在web.config檔案中聲明自訂控制項,在配置節中加入<pages> <controls> <add tagPrefix="cc" assembly="ControlLibrary" namespace="ControlLibrary"/> </controls></pages> |
4. 總結
本次任務裡我們通過繼承WebControl類建立了一個很簡單的星級自訂控制項,隨著學習的加深您將逐漸意識到該控制項實際上包含了自訂控制項開發的基本步驟——建立自控制項、設定樣式、進行呈現,通過把相應的動封裝為不同的方法使代碼看起來更清晰,並且掌握了如何在自訂控制項中使用資源檔,這在自訂控制項使用大量樣式或者指令碼時尤其有用。最後講解了在開發完控制項後如何在頁面中使用。
ASP.NET自訂控制項系列文章
前言
第一天 簡單的星級控制項
第二天 帶有自訂樣式的星級控制項
第三天 使用控制項狀態的星級控制項
第四天 摺疊面板自訂控制項
第五天 可以評分的星級控制項
第六天 可以綁定資料來源的星級控制項
第七天 開發具有豐富特性的清單控制項
第八天 顯示多個條目星級評等的資料繫結控制項
第九天 自訂GridView
第十天 實現分頁功能的DataList
全部源碼下載
本系列文章PDF版本下載