asp.net控件開發基礎(1)
asp。net本身提供了很多控件,提供給我們這些比較懶惰的人使用,我認為控件的作用就在此,因為我們不想重復工作,所以要創建它,這個本身便是一個需求的關系,所以學習控件開發很有意思。 wrox網站上有本書 Professional ASP。NET 2.0 Server Control and Component Development,現在還沒有出版,但網站上放出了代碼,所以正好下載過來學習一下。
我看過前幾章代碼,環環相扣,作者用不同的知識向我們展示同一個效果,所以循序漸進的學下來很有好處。雖然自己對控件開發還不是很熟悉,但我感覺以下幾點很重要,是我自己總結的
1. 了解控件之間的繼承關系
最好是先看看看System。Web。UI命名空間
(1)Control 類,所有的控件都共享的一個類,你需要去看下其里面受保護的幾個方法和屬性,雖然一下看不完,以后會發現常常用到這些方法,大家可以在MSDN看一下其派生類
(2)HtmlTextWriter 類,不得不了解的一個類,主要工作就是我們寫的標記字符和文本輸出
2. 重寫方法
(1) 必須繼承Control類
(2) 重寫Control類的Render方法,這個是必須的,因為其他控件都繼承了Control 類類,所以幾乎所有控件都有這個方法
3. 熟悉元數據
大家都知道asp。net控件屬性在編輯器上是分類的,如外觀,行為,布局等,每個屬性還給出了解釋。簡單的元數據就是起到這個作用,當然你也可以不加,但使用了元數據讓人感到有親切感,寫法如
下
[CategoryAttribute("Appearance")]
要使用元數據,必須引用System。ComponentModel命名控件,一般你如果寫組件的話,不可能不用到這樣類庫。具體的MSDN上有所介紹。
一. 輸出字符串
說多了沒意思,還是來演練吧。首先你得了解HTML。來看下面代碼,效果就是輸出HTML到客戶端
示例一
using System.Web.UI;
namespace CustomComponents
{
/// <summary>
/// Summary description for CreditCardForm
/// </summary>
public class CreditCardForm1 : Control
{
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<table style='width:287px;height:124px;border-width:0;'>");
writer.Write("<tr>");
writer.Write("<td><strong>Payment Method</strong></td>");
writer.Write("<td>");
writer.Write("<select name='PaymentMethod' id='PaymentMethod' style='width:100%;'>");
writer.Write("<option value='0'>Visa</option>");
writer.Write("<option value='1'>MasterCard</option>");
writer.Write("</select>");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td><strong>Credit Card No.</strong></td>");
writer.Write("<td><input name='CreditCardNo' id='CreditCardNo' type='text' /></td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td><strong>Cardholder's Name</strong></td>");
writer.Write("<td><input name='CardholderName' id='CardholderName' type='text' /></td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td><strong>Expiration Date</strong></td>");
writer.Write("<td>");
writer.Write("<select name='Month' id='Month'>");
for (int day = 1; day < 13; day++)
{
if (day < 10)
writer.Write("<option value='" + day.ToString() + "'>" + "0" + day.ToString() + "</option>");
else
writer.Write("<option value='" + day.ToString() + "'>" + day.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write(" ");
writer.Write("<select name='Year' id='Year'>");
for (int year = 2005; year < 2015; year++)
{
writer.Write("<option value='" + year.ToString() + "'>" + year.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td align='center' colspan='2'>");
writer.Write("<input type='submit' value='Submit' />");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("</table>");
base.Render(writer);
}
}
}
效果很簡單,其實就一直在輸出HTML再加幾個屬性,大家可以直接把代碼放在App_Code文件夾里,就可自動編譯,當然也可以創建web控件庫。注意要繼承Control類,重寫Render方法,用HtmlTextWriter類的Write輸出HTML
使用控件
(1). 需要先注冊一下
<%@ Register TagPrefix="custom" Namespace="CustomComponents" %>
(2) 然后就使用標簽輸出效果
<custom:CreditCardForm1 runat="server" ID="ccf" />
下為效果圖
二. 改善,加入屬性和元數據
可能上面做出的 控件毫無用處,但卻可以讓你熟悉一下步驟,上面的控件定的很死,沒有定義任何屬性,用處不大,下面來改造我們來定義常用屬性,然后再輸出,這樣我們就可以修改控件的屬性了,
示例二
using System.Web.UI;
using System.ComponentModel;
namespace CustomComponents
{
[DefaultPropertyAttribute("CardholderNameText")]
[ToolboxData(@"<{0}:CreditCardForm2
PaymentMethodText='信用卡類型' CreditCardNoText='信用卡卡號'
CardholderNameText='信用卡持有者姓名' SubmitButtonText = '提交'
runat='server'></{0}:CreditCardForm2>")
]
public class CreditCardForm2 : Control
{
private string paymentMethodText = "信用卡類型";
private string creditCardNoText = "信用卡卡號";
private string cardholderNameText = "信用卡持有者姓名";
private string expirationDateText = "最后使用時間";
private string submitButtonText = "提交";
[BrowsableAttribute(true)]
[DescriptionAttribute("獲取和設置信用卡類型")]
[DefaultValueAttribute("信用卡類型")]
[CategoryAttribute("Appearance")]
public virtual string PaymentMethodText
{
get { return this.paymentMethodText; }
set { this.paymentMethodText = value; }
}
[BrowsableAttribute(true)]
[DescriptionAttribute("獲取或設置信用卡卡號")]
[DefaultValueAttribute("信用卡卡號")]
[CategoryAttribute("Appearance")]
public virtual string CreditCardNoText
{
get { return this.creditCardNoText; }
set { this.creditCardNoText = value; }
}
[BrowsableAttribute(true)]
[DescriptionAttribute("獲取或設置信用卡持有者姓名")]
[DefaultValueAttribute("信用卡持有者姓名")]
[CategoryAttribute("Appearance")]
public virtual string CardholderNameText
{
get { return this.cardholderNameText; }
set { this.cardholderNameText = value; }
}
[BrowsableAttribute(true)]
[DescriptionAttribute("獲取或設置最后使用時間")]
[DefaultValueAttribute("最后使用時間")]
[CategoryAttribute("Appearance")]
public virtual string ExpirationDateText
{
get { return this.expirationDateText; }
set { this.expirationDateText = value; }
}
[BrowsableAttribute(true)]
[DescriptionAttribute("獲取或設置按鈕標簽")]
[DefaultValueAttribute("提交")]
[CategoryAttribute("Appearance")]
public virtual string SubmitButtonText
{
get { return this.submitButtonText; }
set { this.submitButtonText = value; }
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<table style='width:287px;height:124px;border-width:0;'>");
writer.Write("<tr>");
writer.Write("<td>" + PaymentMethodText + "</td>");
writer.Write("<td>");
writer.Write("<select name='PaymentMethod' id='PaymentMethod' style='width:100%;'>");
writer.Write("<option value='0'>Visa</option>");
writer.Write("<option value='1'>MasterCard</option>");
writer.Write("</select>");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td>" + CreditCardNoText + "</td>");
writer.Write("<td><input name='CreditCardNo' id='CreditCardNo' type='text' /></td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td>" + CardholderNameText + "</td>");
writer.Write("<td><input name='CardholderName' id='CardholderName' type='text' /></td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td>" + ExpirationDateText + "</td>");
writer.Write("<td>");
writer.Write("<select name='Month' id='Month'>");
for (int day = 1; day < 13; day++)
{
if (day < 10)
writer.Write("<option value='" + day.ToString() + "'>" + "0" + day.ToString() + "</option>");
else
writer.Write("<option value='" + day.ToString() + "'>" + day.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write(" ");
writer.Write("<select name='Year' id='Year'>");
for (int year = 2005; year < 2015; year++)
{
writer.Write("<option value='" + year.ToString() + "'>" + year.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("<tr>");
writer.Write("<td align='center' colspan='2'>");
writer.Write("<input type='submit' value='" + SubmitButtonText + "' />");
writer.Write("</td>");
writer.Write("</tr>");
writer.Write("</table>");
base.Render(writer);
}
}
}
上面我們接觸到了元數據了,意思應該很好理解,為了測試元數據的作用,大家可以新建一個類庫項目,然后把寫的代碼放這個項目里面,接著web網站引用這個項目,成功生成以后,你會發現工具箱已經自動幫你加上了這幾個控件
接著你要做的工作就是拖動你需要的控件,然后你會在屬性面板看到下圖
然后你再結合代碼中的元數據,應該就知道大概意思了。(可以根據你的理解結合MSDN看)
三. 再次改善,淘汰用Write方法以字符串的方式輸出HTML
接著我們繼續發現問題,我們發現我們除了定義幾個需要自己來修改的屬性外,還是要用來大量的字符串用來輸出HTML,而且容易輸錯。所以HtmlTextWriter類提供幾個有用的方法用來代替。
(1)AddStyleAttribute方法 為標簽添加樣式屬性
(2)AddAttribute方法 為標簽添加屬性
(3)RenderBeginTag 開始寫入標簽頭 如<table。。。。>
(4)RenderEndTag 寫入標簽尾部,如</table>
這里有幾點需要特別注意。
一. 因為其定義方式跟我們平時定義方式不同,我們平時寫HTML時,是先寫標簽開頭,再寫標簽的屬性。如<table borderwidth="0">,然而我們在使用上面幾個方法時,需要有先后順序,我們需要先定義標簽的屬性和樣式,然后再輸出標簽頭。
二.標簽頭和尾,需一一對應。可以理解為嵌套關系。最好的理解方法就是輸出代碼后,查看源文件,再結合原來定義的代碼來看。還是看代碼比較容易說明,由于CreditCardForm2已經定義了我們需要的屬性,而我們現在要做的只是用標簽的形式來替代字符串的形式,所以只需要繼承CreditCardForm2類,重寫Render方法即可
示例三
{
writer.AddStyleAttribute(HtmlTextWriterStyle.BorderWidth, "0");
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("<strong>" + PaymentMethodText + "</strong>");
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Name, "PaymentMethod");
writer.AddAttribute(HtmlTextWriterAttribute.Id, "PaymentMethod");
writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
writer.AddAttribute(HtmlTextWriterAttribute.Value, "0");
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.Write("Visa");
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Value, "1");
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.Write("MasterCard");
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("<strong>" + CreditCardNoText + "</strong>");
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Name, "CreditCardNo");
writer.AddAttribute(HtmlTextWriterAttribute.Id, "CreditCardNo");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("<strong>" + CardholderNameText + "</strong>");
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Name, "CardholderName");
writer.AddAttribute(HtmlTextWriterAttribute.Id, "CardholderName");
writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("<strong>" + ExpirationDateText + "</strong>");
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Name, "Month");
writer.AddAttribute(HtmlTextWriterAttribute.Id, "Month");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
for (int day = 1; day < 13; day++)
{
writer.AddAttribute(HtmlTextWriterAttribute.Value, day.ToString());
writer.RenderBeginTag(HtmlTextWriterTag.Option);
if (day < 10)
writer.Write("0" + day.ToString());
else
writer.Write(day);
writer.RenderEndTag();
}
writer.RenderEndTag();
writer.Write(" ");
writer.AddAttribute(HtmlTextWriterAttribute.Name, "Year");
writer.AddAttribute(HtmlTextWriterAttribute.Id, "Year");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
for (int year = 2005; year < 2015; year++)
{
writer.AddAttribute(HtmlTextWriterAttribute.Value, year.ToString());
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.Write(year);
writer.RenderEndTag();
}
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(HtmlTextWriterAttribute.Align, "center");
writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "submit");
writer.AddAttribute(HtmlTextWriterAttribute.Value, SubmitButtonText);
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
實現的效果雖然一樣,但上面的代碼是不是漂亮很多,而且不容易輸錯。這也是所提倡的做法
四. 未使用視圖狀態的后果
還是視圖狀態,關于視圖狀態大家可以參考MSDN和相關文章, 看以下的示例,還是CreditCardForm3這個控件








首次加載效果
點擊按鈕以后
五。使用視圖狀態改善效果
前提條件是你未禁用視圖狀態,繼承CreditCardForm3,改寫每個屬性
{
get { return ViewState["PaymentMethodText"] != null ? (string)ViewState["PaymentMethodText"] : "信用卡類型"; }
set { ViewState["PaymentMethodText"] = value; }
}
public override string CreditCardNoText
{
get { return ViewState["CreditCardNoText"] != null ? (string)ViewState["CreditCardNoText"] : "信用卡卡號"; }
set { ViewState["CreditCardNoText"] = value; }
}
public override string CardholderNameText
{
get { return ViewState["CardholderNameText"] != null ? (string)ViewState["CardholderNameText"] : "信用卡持有者姓名"; }
set { ViewState["CardholderNameText"] = value; }
}
public override string ExpirationDateText
{
get { return ViewState["ExpirationDateText"] != null ? (string)ViewState["ExpirationDateText"] : "最后使用時間"; }
set { ViewState["ExpirationDateText"] = value; }
}
public override string SubmitButtonText
{
get { return ViewState["SubmitButtonText"] != null ? (string)ViewState["SubmitButtonText"] : "提交"; }
set { ViewState["SubmitButtonText"] = value; }
}
以上全為個人見解,如有錯誤,希望大家指出。