轉帖|其它|編輯:郝浩|2009-03-11 10:28:43.000|閱讀 1394 次
概述:.net中開發復合控件
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
1)開發復合控件
每個控件都具有從 System.Web.UI.Control 繼承的 Controls 屬性。這是表示控件的子控件(如果有)的集合屬性。如果控件未用 ParseChildrenAttribute 標記,或是標記為 ParseChildrenAttribute(Childrenasproperties = false),則當控件在頁上以聲明方式使用時,ASP.NET 頁框架將應用以下分析邏輯:
如果分析器在控件的標記內遇到嵌套控件,它將創建嵌套控件的實例并將它們添加到控件的 Controls 屬性。標記之間的文本添加為 LiteralControl。任何其他嵌套元素都生成分析器錯誤。
如果自定義控件是從 WebControl 派生的,它將不具有示例中描述的分析邏輯,因為 WebControl 是用 ParseChildrenAttribute(ChildrenAsProperties = true) 標記的,用它可以指示當在頁上以聲明方式使用控件時,嵌套在服務器控件標記內的 XML 元素是應視為屬性還是應視為子控件。無法繼承此類。
以常見的DropDownList為例,下面是DropDownList控件基本使用模式:
<asp:DropDownList id=”drop” ruant=”server”>
<asp:ListItem>item1<asp:ListItem>
… …
<asp:ListItem>itemn<asp:ListItem>
</asp:DropDownList>
我們說過web服務器控件都是從WebControl類派生,這樣.NET框架解析該控件時,ASP.NET自動將DropDownList的ChildrenAsProperties 屬性設置為true,告訴框架在建立DropDownList時,ListItem應該看成是子控件而不是DropDownList的屬性。這樣框架就會建立子控件ListItem對象。
一個控件到底是屬性還是子控件有什么區別嗎?其實屬性和自控件主要區別是包容容器的不同。當一個字段被當作屬性時,這個屬性其實是該類的一個成員,例如DropDownList的ID,它是DropDownList的屬性,因此DropDownList的定義應該類似如下:
class DropDownList:WebControl
{int ID;
… …}
而ListItem是子控件使得ListItem和DropDownList是邏輯上分離的,也就是說ListItem提供一種接口,這樣復合這種接口的控件,都可以作為它的父控件(或者說容器),
正式因為這個原因,所以對于ListBox控件可能有如下使用方式
<asp:ListBox id=”list” ruant=”server”>
<asp:ListItem>item1<asp:ListItem>
… …
<asp:ListItem>itemn<asp:ListItem>
</asp:ListBox>
讀者可以看到,作為子控件的ListItem很容易“融合”在ListBox里,把ListBox當作其容器。
接下來我們要開發功能和DropDownList控件類似的Sorter控件,所以讀者頁可能已經感覺到,將要建立的控件使用應該類似如下:
<Community:Sorter id=”sorter” ruant=”server”>
<asp:ListItem>item1<asp:ListItem>
… …
<asp:ListItem>itemn<asp:ListItem>
</Community:Sorter>
注意:可以通過使用類撰寫組合現有控件來創作新控件。復合控件等效于使用 ASP.NET 頁語法創作的用戶控件。用戶控件和復合控件之間的主要差異是用戶控件保持為 .ascx 文本文件,而復合控件則經過編譯并保持在程序集中。
在開發Sorter自定義復合控件前,先看一下常規開發的兩個主要步驟:
A)重寫從 Control 繼承的受保護的 CreateChildControls 方法,以創建子控件的實例并將它們添加到控件集合。前面說過既然ListItem是子控件就需要將它添加到父容器里,例如如果是DropDownList控件其父容器是DropDownList,如果是ListBox控件,則父容器是ListBox。下面顯示了如何重新CreateChildControls
public class Composition1 : Control, INamingContainer {
... ...
protected override void CreateChildControls() {
//加入第一個控件
this.Controls.Add(new LiteralControl("<h3>" + "值:"));
//加入第二個控件
TextBox box = new TextBox();
box.Text = "0";
this.Controls.Add(box);
//加入第三個控件
this.Controls.Add(new LiteralControl("</h3>"));
}
這樣在控件樹里加入了三個控件:兩個LiteralControl和一個TextBox控件。其中第一個LiteralControl的值為“<h3>值”,第二個LiteralControl的值為“</h3>”,TextBox的值為0。這樣如果在服務器發送到瀏覽器后,生成的HTML代碼就是“<h3>0</h3>”。
當將子控件加入控件樹以后,就可以從索引為零的編號獲取控件樹里的控件,加入后頁面控件樹示意圖如下:
Page
|
|--LiteralControl (Controls[0])
|
|--TextBox (Controls[1])
|
|--LiteralControl (Controls[2])
其中Page是整個控件樹的樹根,每一個子控件根據加入順序的位置的不同依次加入控件樹。當需要獲取控件樹時,可以使用索引獲取,例如讀寫TextBox的代碼如下:
//讀取TextBox控件的值,并賦給value變量
string value=((TextBox)Controls[1]).Text;
//將value值寫入TextBox控件里
((TextBox)Controls[1]).Text = value.ToString();
這里Controls[1]獲取的就是第二個控件,也就是TextBox,然后使用TextBox類進行強制轉換,獲取Text值后賦值給value。寫如的方法和此類似。
B)如果復合控件的新實例將在頁上重復創建,請實現 System.Web.UI.INamingContainer 接口。這是不具有方法的標記接口。當用控件實現時,ASP.NET 頁框架將在此控件下創建新的命名范圍。這確保了子控件在控件層次結構樹中具有唯一的 ID。 因為子控件會提供呈現邏輯,所以不必重寫 Render 方法。可以公開合成子控件屬性的屬性。
在ASP.NET提供的服務器控件里都實現了InamingContainer接口,所以您可以在一個頁面生多次使用button、TextBox等這樣的控件。但是在下面介紹的Sorter自定義控件里,根據實際需求,一個頁面只要一個Sorter自定義控件就可以了,所以Sorter自定義控件沒有實現InamingContainer接口。
由于將要開發的復合控件還需要實現數據回發、事件處理等,下面再介紹這些基礎的內容。
2)開發處理回發數據的自定義(非復合)控件 Sorter
檢查回發(輸入)數據的控件必須實現 System.Web.UI.IPostBackDataHandler 接口。這將向 ASP.NET 頁框架發出信號,指出控件應參與回發數據處理。頁框架將輸入數據作為鍵/值對傳遞給此接口的 LoadPostData 方法。請看下面代碼:
using System;
using System.Web;
using System.Web.UI;
using System.Collections.Specialized;
namespace CustomControls{
public class MyTextBox: Control, IPostBackDataHandler {
public String Text {
get { return (String) ViewState["Text"]; }
set { ViewState["Text"] = value; }
}
public event EventHandler TextChanged;
public virtual bool LoadPostData(string postDataKey, NameValueCollection values)
{
String presentValue = Text;
String postedValue = values[postDataKey];
if (!presentValue.Equals(postedValue)){
Text = postedValue;
return true;
}
return false;
}
public virtual void RaisePostDataChangedEvent() {
OnTextChanged(EventArgs.Empty);
}
protected virtual void OnTextChanged(EventArgs e){
if (TextChanged != null)
TextChanged(this,e);
}
protected override void Render(HtmlTextWriter output) {
output.AddAttribute(HtmlTextWriterAttribute.Type, "text");
output.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
output.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
output.RenderBeginTag(HtmlTextWriterTag.Input);
output.RenderEndTag();
}
}
}
若要使控件能夠檢查客戶端發回的窗體數據,控件必須實現 System.Web.UI.IPostBackDataHandler 接口。此接口的協定允許控件確定是否在回發后改變其狀態以及引發相應的事件。IPostBackDataHandler 接口包含兩個方法。
public interface IPostBackDataHandler{
public bool LoadPostData(string postDataKey, NameValueCollection postCollection);
public void RaisePostDataChangedEvent();
}
回發后,頁框架在發送的內容中搜索與實現 IPostBackDataHandler 的服務器控件的 UniqueID 匹配的值。然后,頁框架按順序在每個實現該接口的控件上調用 LoadPostData。LoadPostData 的兩個參數是:標識控件的關鍵字以及包含發送數據的集合 NameValueCollection。通常實現 LoadPostData,以便在回發后更新控件的狀態。以下示例說明用于自定義文本框 (TextBox) 控件的 LoadPostData 實現。
public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) {
string presentV
該文章轉載自1024k:
alue = text;
string postedValue = postCollection[postDataKey];
if (!presentValue.Equals(postedValue)){
Text = postedValue;
return true;
}
return false;
}
如果控件狀態因回發而更改,則 LoadPostData 返回 true;否則返回 false。頁框架跟蹤所有返回 true 的控件并在這些控件上調用 RaisePostDataChangedEvent。更改事件(如果有)就是從該方法引發的。因此,回發數據處理分兩個階段進行,即更新狀態和引發更改通知。這可防止在加載回發數據過程中引發更改通知,在該過程中,更改通知可能在各控件加載回發數據之前錯誤地修改狀態。以下代碼片段顯示了用于自定義文本框 (TextBox) 控件的 RaisePostDataChanged 實現。
public virtual void RaisePostDataChangedEvent() {
OnTextChanged(EventArgs.Empty);
}
呈現邏輯必須為控件的名稱特性分配 UniqueID。否則,頁框架就無法將回發數據傳送給控件。如果控件發出多個窗體元素,則至少有一個元素必須具有與控件 UniqueID 對應的名稱特性。以下代碼片段將 UniqueID 分配給名稱特性。
protected override void Render(HtmlTextWriter output)
{
output.AddAttribute(HtmlTextWriterAttribute.Type, "text");
output.AddAttribute(HtmlTextWriterAttribute.Value, this.Text);
output.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
output.RenderBeginTag(HtmlTextWriterTag.Input);
output.RenderEndTag();
}
<%@ Register TagPrefix="Custom" Namespace="CustomControls" Assembly = "CustomControls" %>
<html>
<script language="C#" runat=server>
private StringBuilder message = new StringBuilder("");
private void Text_Changed(Object sender,EventArgs e){
message.Append("The text in" + sender.ToString()+ " was changed.");
message.Append("<br>You entered " + Server.HtmlEncode(Box.Text) +".");
}
protected override void Render(HtmlTextWriter output) {
base.Render(output);
output.Write(message.ToString());
}
</script>
<body>
<form method="POST" action="MyTextBox.aspx" runat=server>
Enter your name: <Custom:MyTextBox Text=" " OnTextChanged = "Text_Changed" id = "Box" runat=server/>
<br><br>
<asp:Button Text = "Submit" runat = server/>
</form>
</body>
</html>
這里再次強調一下UniqueID,上面我們使用了一個ID為Box的MyTextBox控件,介紹我們在服務器控件使用了兩個MyTextBox控件如下
<Custom:MyTextBox Text="this is a mytextbox1 " id = "Box1" runat=server/>
<Custom:MyTextBox Text="this is amytextbox2" id = "Box1" runat=server/>
那么當頁面回發時如何區分獲取這兩個控件值呢?
這里首先說明,在上面MyTextBox自定義控件里并沒有實現InamingContainer接口,所以不能夠再頁面實現兩個MyTextBox控件,現在是假設實現了InamingContainer接口,如何分別獲取Box1和Box2的值。
首先可以更改LoadPostData方法如下如下:
public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) {
string presentValue = Text;
string postedValue = postCollection[UniqueID];
if (!presentValue.Equals(postedValue)){
Text = postedValue;
return true;
}
return false;
}
LoadPostData的第二個參數是NameValueCollection類型,可以使用名值對的方式獲取數據。
對于第一個MyTextBox來說,其ID為Box1,所以此時UniqueID就是Box1,通過postCollection[UniqueID]就可以獲取傳遞的文本值“this is a mytextbox1”。
對于第二個MyTextBox來說,其ID為Box2,所以此時UniqueID就是Box2,通過postCollection[UniqueID]就可以獲取傳遞的文本值“this is a mytextbox2”。
那么數據又如何改變呢?
對于第一個MyTextBox,它首先的文本是“this is a mytextbox1”,假設我們在*.aspx里改變其文本為“mytextbox1 values”,那么數據回發到服務器時,會將現在的文本和原來的文本進行畢竟,那么原來的文本是怎么保存的呢?答案是通過ViewState,讀者應該看到在MyTextBox里有如下代碼
public String Text {
get { return (String) ViewState["Text"]; }
set { ViewState["Text"] = value; }
}
它會保存上一次的數據,也就是“this is a mytextbox1”,然后和本次提交的數據“mytextbox1 values”進行畢竟,比較是通過是否相等進行的(換句話說比較文本有沒有改變),如下
if (!presentValue.Equals(postedValue)){
Text = postedValue;
return true;
}
如果當前的數據presentValue(它的現在的值是“this is a textbox1”)和postedValue(它的現在的值是“mytextbox1 values”)不等則將postedValue賦值給Text,以便回發到客戶端進行更新TextBox的值。然后再返回true。
在返回true非常重要,因此系統再保存了當前值mytextbox1 values以后,并不意味用戶的處理已經結束了,可能用戶還定義了事件,此時就可以使用RaisePostDataChangedEvent進一步處理事件,如下
public virtual void RaisePostDataChangedEvent() {
OnTextChanged(EventArgs.Empty);
}
我們看到再該實現里調用了OnTextChanged方法,而在OnTextChanged方法里調用了TextChanged事件,所以用戶就可以在*.aspx頁面里使用如下方式觸發自定義事件處理內容:
private void Text_Changed(Object sender,EventArgs e){}
…
<Custom:MyTextBox Text=" " OnTextChanged = "Text_Changed" id = "Box" runat=server/>
3)自定義復合控件處理事件
下面代碼定義了一個復合控件 Composition2,該控件將兩個按鈕控件(名為 Add 和 Subtract)添加到復合控件里,并為按鈕的 Click 事件提供事件處理方法。這些方法增加和減少 Composition2 的 Value 屬性。Composition2 的 CreateChildControls 方法創建引用這些方法的事件處理程序(委托)的實例,并將委托附加到 Button 實例的 Click 事件。最后得到一個進行自己的事件處理的控件——單擊 Add 按鈕時,文本框中的值增加;單擊 Subtract 按鈕時,值減少。
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace CompositionSampleControls {
public class Composition2 : Control, INamingContainer {
public int Value {
get {
this.EnsureChildControls();
return Int32.Parse(((TextBox)Controls[1]).Text);
}
set {
this.EnsureChildControls();
((TextBox)Controls[1]).Text = value.ToString();
}
}
protected override void CreateChildControls() {
// 添加文本控件
this.Controls.Add(new LiteralControl("<h3>" + "值:"));
// 添加文本框
TextBox box = new TextBox();
box.Text = "0";
this.Controls.Add(box);
// 添加文本控件
this.Controls.Add(new LiteralControl("</h3>"));
// 添加“加”按鈕
Button addButton = new Button();
&
該文章轉載自1024k:
該文章轉載自1024k:
nbsp; addButton.text = "加";
addButton.Click += new EventHandler(this.AddBtn_Click);
this.Controls.Add(addButton);
// 添加文本控件
this.Controls.Add(new LiteralControl(" | "));
// 添加“減”按鈕
Button subtractButton = new Button();
subtractButton.Text = "減";
subtractButton.Click += new EventHandler(this.SubtractBtn_Click);
this.Controls.Add(subtractButton);
}
private void AddBtn_Click(Object sender, EventArgs e) {
this.Value++;
}
private void SubtractBtn_Click(Object sender, EventArgs e) {
this.Value--;
}
}
}
在這種復合控件里,事件的處理由控件內部進行處理,所以如果我們在頁面*.aspx使用該控件可能類似的代碼如下:
<CompositionSampleControls:Composition2 id="MyControl" runat=server/>
讀者看到,這里僅僅引用了復合控件,而對于數據添加/刪除處理都是由控件內部來實現。
4)復合控件可以定義自定義事件,通過引發該事件來響應其子控件引發的事件。
上面介紹的復合控件將事件的具體處理都在其內部實現了,所以使用面叫窄,例如如果用戶每一次單擊Add添加2,每一次單擊Subtract減少2,那么我們還需要到自定義控件內部更改代碼類似如下:
private void AddBtn_Click(Object sender, EventArgs e) {
this.Value +=2;
}
private void SubtractBtn_Click(Object sender, EventArgs e) {
this.Value-=2;
}
可以該控件使用人員還必須了解控件內部的運行機制,這非常不方便使用,所以我們應該自定義帶有事件的復合控件。
下面的示例顯示復合控件 Composition3,該控件引發自定義事件 Change 以響應 TextBox 子控件的 TextChanged 事件。
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace CompositionSampleControls {
public class Composition3 : Control, INamingContainer {
public event EventHandler Change;
public int Value {
get {
this.EnsureChildControls();
return Int32.Parse(((TextBox)Controls[1]).Text);
}
set {
this.EnsureChildControls();
((TextBox)Controls[1]).Text = value.ToString();
}
}
protected void OnChange(EventArgs e) {
Change(this, e);
}
protected override void CreateChildControls() {
// 添加文本控件
this.Controls.Add(new LiteralControl("<h3>" + "值:"));
// 添加文本框
TextBox box = new TextBox();
box.Text = "0";
box.TextChanged += new EventHandler(this.TextBox_Change);
this.Controls.Add(box);
// 添加文本控件
this.Controls.Add(new LiteralControl("</h3>"));
// 添加“加”按鈕
Button addButton = new Button();
addButton.Text = "加";
addButton.Click += new EventHandler(this.AddBtn_Click);
this.Controls.Add(addButton);
// 添加文本控件
this.Controls.Add(new LiteralControl(" | "));
// 添加“減”按鈕
Button subtractButton = new Button();
subtractButton.Text = "減";
subtractButton.Click += new EventHandler(this.SubtractBtn_Click);
this.Controls.Add(subtractButton);
}
private void TextBox_Change(Object sender, EventArgs e) {
OnChange(EventArgs.Empty);
}
private void AddBtn_Click(Object sender, EventArgs e) {
this.Value++;
OnChange(EventArgs.Empty);
}
private void SubtractBtn_Click(Object sender, EventArgs e) {
this.Value--;
OnChange(EventArgs.Empty);
}
}
}
實現方法如下:
(a)自定義 Change 事件通過標準事件模式定義。(該模式包括受保護的 OnChange 方法的定義,該方法將引發 Change 事件。)
public event EventHandler Change;
protected void OnChange(EventArgs e) {
Change(this, e);}
前面也介紹過了,OnChange這種命名方式是為了便于和微軟的資料相互一致,我們定義了OnChange方法后,就可以在*.aspx里使用類似如下代碼定義事件具體的處理:
<CompositionSampleControls:Composition3 id="MyControl" OnChange="Composition3_Change" runat=server/>
<script language="C#" runat=server>
private void Composition3_Change(Object sender, EventArgs e) {
if (MyControl.Value < 0) {
MyControl.Value = 0;
}
}
</script>
讀者此時應該明白一直使用類似OnClick、OnLoad的意義:通過代理進行鏈接,所以上面代碼也可以寫成更為明了的方式
Composition3.Change += new EventHander(Composition3_Change)
(b) 為 TextBox 的 TextChanged 事件定義了一個事件處理方法。該方法通過調用 OnChange 方法來引發 Change 事件。
private void TextBox_Change(Object sender, EventArgs e) {
OnChange(EventArgs.Empty);
}
(c)CreateChildControls 方法創建一個事件處理程序的實例,該實例引用上述方法并將事件處理程序附加到 TextBox 實例的 TextChanged 事件。
protected override void CreateChildControls() {
..
TextBox box = new TextBox();
box.TextChanged += new EventHandler(this.TextBox_Change);
...
}
Change 事件可以由承載控件的頁來處理,如下面的示例所示。在此示例中,頁為 Change 事件提供事件處理方法。如果用戶輸入的數字為負,該事件將 Value 屬性設置為零。
定義好的自定義控件,就可以按照如下代碼引用
<%@ Register TagPrefix="CompositionSampleControls" Namespace="CompositionSampleControls" Assembly="CompositionSampleControls" %>
<html>
<script language="C#" runat=server>
private void Composition3_Change(Object sender, EventArgs e) {
if (MyControl.Value < 0) {
MyControl.Value = 0;
}
}
</script>
<body>
<form method="POST" action="Composition3.aspx" runat=server>
<CompositionSampleControls:Composition3 id="MyControl"
OnChange="Composition3_Change" runat=server/>
</form>
</body>
</html>
5)維護狀態
每個 Web 窗體控件都有一個 State 屬性(從 Control 繼承),該屬性使 Web 窗體控件能夠參與 State
該文章轉載自1024k:
管理。State 的類型為 Sytem.Web.UI.StateBag,這是等效于哈希表的數據結構。控件可以將數據作為鍵/值對保存在 State 中。State 通過 ASP.NET 頁框架保持為字符串變量,并以隱藏變量的形式與客戶端之間往返。回發時,頁框架分析來自隱藏變量的輸入字符串,并在頁的控件層次結構中填充每個控件的 State 屬性。通過使用 State 屬性,控件可以還原其狀態(將屬性和字段設置為它們回發前的值)。
5.9.3 Sorter自定義控件
下面介紹Sorter自定義控件,首先導入命名空間
namespace ASPNET.StarterKit.Communities {
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Collections;
using System.ComponentModel;
using System.Collections.Specialized;
Sorter類文件用于生成Sorter控件,
[ParseChildren(false), ControlBuilder(typeof(SorterControlBuilder)),
Designer(typeof(ASPNET.StarterKit.Communities.CommunityDesigner)) ]
public class Sorter : WebControl, IPostBackDataHandler {
在這段代碼里,ParseChildren設置為false,這是因為Sorter控件從WebControl派生,默認ParseChildren將被設置為true。ParseChildren用于指示頁面分析器如何分析Sorter直接的XML標記,當將ParseChildren顯式設置為falsie,頁框架將認為Sorter直接是屬性而非子控件,下面是Sorter在頁面里的典型應用
<community:Sorter id="Sorter" align="right" runat="Server">
<ListItem Text="Default Order" value="Default" />
<ListItem Text="Date Posted" value="DateCreated"/>
<ListItem Text="Title" value="Title"/>
<ListItem Text="Popularity" value="ViewCount"/>
<ListItem Text="Topic" value="Topic" />
<ListItem Text="Author" value="Author" />
<ListItem Text="Rating" value="Rating" />
</community:Sorter>
通過將ParseChildren設置為false告訴系統,<community:Sorter></community:Sorter>之間的<ListItem>
</ListItem>標記應該看生是Sorter屬性,這和常規使用的DropDownList默認將ListItem當作子控件并不一樣。那么為什么這里設置為false呢?
筆者認為,將ParseChildren設置為false能夠提供更為廣闊的自定義控件的靈活性,以常規的DropDownList為例,下面的使用是錯誤的:
<asp:DropDownList id="Drop" align="right" runat="Server">
<asp:ListItem Text="Default Order" value="Default" />
<asp:ListItem Text="Date Posted" value="DateCreated"/>
<ListItem Text="Title" value="Title"/>
this is a dropdown
</asp:DropDownList>
就是因為DropDownList將ParseChildren設置為true,它只能夠解析內部的子控件,而對于<ListItem Text="Title" value="Title"/>和this is a dropdown這樣的文本則不能夠解析,提示發生錯誤。
但是如果使用Sorter自定義控件,則如下寫法是可以的
<Community:Sorter id="Drop" align="right" runat="Server">
<asp:ListItem Text="Default Order" value="Default" />
<asp:ListItem Text="Date Posted" value="DateCreated"/>
<ListItem Text="Title" value="Title"/>
this is a dropdown
</Community:Sorter>
因此Sorter將其內部數據并不看成子控件,后來還可以看到,通過派生的SorterControlBuilder類(下敘述),使得代碼對于類似this is a dropdown這樣的文本進行了過濾。
ASP.NET 頁框架使用稱為控件生成器的類來處理頁上控件標記中的聲明。每個 Web 窗體控件都與默認的控件生成器類 System.Web.UI.ControlBuilder 關聯。默認的控件生成器為它在控件標記中遇到的每個嵌套控件將子控件添加到 Controls 集合。另外,它為嵌套控件標記之間的文本添加 Literal 控件。通過將自定義控件生成器類與控件關聯,可以重寫此默認行為。這通過對控件應用控件生成器屬性來實現,Sorter使用的重新代碼如下:
[ControlBuilder(typeof(SorterControlBuilder))]
public class Sorter : WebControl, IPostBackDataHandler {...}
以上方括號里的元素為公共語言運行庫屬性,該屬性將 SorterControlBuilder類與 Sorter控件關聯。通過從 ControlBuilder 派生并重寫SorterControlBuilder方法,自定義了Sorter的生成器。
在后面代碼我們可以看到,Sorter定義一個自定義控件生成器,它重寫從 ControlBuilder 繼承的 GetChildControlType 方法。此方法返回要添加的控件類型,并可用來決定將要添加哪些控件。在Sorter中,控件生成器僅在標記名稱為“listItem”或者“asp:listItem”時才添加子控件。
Designer可以擴展自定義web服務器控件的模式行為。在Sorter的使用類似如下
[Designer(typeof(ASPNET.StarterKit.Communities.CommunityDesigner)) ]
public class Sorter : WebControl, IPostBackDataHandler {…}
表示具體的擴展類由ASPNET.StarterKit.Communities.CommunityDesigner類實現,后面會由介紹
接下來定義一個OrderChanged事件,并定義了升序或者降序時顯示的文本屬性。
public event EventHandler OrderChanged
ListItemCollection _items = new ListItemCollection();
string _ascendingText = "Ascending";
public string AscendingText
{ get { return _ascendingText; } set { _ascendingText = value; } }
string _descendingText = "Descending";
public string DescendingText
{ get { return _descendingText; } set { _descendingText = value; } }
請讀者明白一個Sorter控件其實包含了兩個DropDownList控件,,但是對于有便那個下拉框它的文本顯示是固定的,要么是升序(Ascending)要么是降序(Descending),所以在用戶使用該控件值,這個DropDownList的值并不需要用戶維護,而是由該Sorter控件內部自己維護,所以這里定義了AscendingText和DescendingText屬性。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:個人博客