ASP.NET控件開發(fā)基礎(chǔ)之自定義控件淺析
ASP.NET本身提供了很多控件,提供給我們這些比較懶惰的人使用,我認為控件的作用就在此,因為我們不想重復工作,所以要創(chuàng)建它,這個本身便是一個需求的關(guān)系,所以學習自定義控件開發(fā)很有意思.
wrox網(wǎng)站上有本書 Professional ASP.NET 2.0 Server Control and Component Development
現(xiàn)在還沒有出版,但網(wǎng)站上放出了代碼,所以正好下載過來學習一下.
我看過前幾章代碼,環(huán)環(huán)相扣,作者用不同的知識向我們展示同一個效果,所以循序漸進的學下來很有好處.
雖然自己對控件開發(fā)還不是很熟悉,但我感覺對于ASP.NET控件開發(fā)基礎(chǔ)中自定義控件以下幾點很重要,是我自己總結(jié)的
1.了解ASP.NET自定義控件之間的繼承關(guān)系
***是先看看看System.Web.UI命名空間
(1)Control 類,所有的控件都共享的一個類,你需要去看下其里面受保護的幾個方法和屬性,雖然一下看不完,以后會發(fā)現(xiàn)常常用到這些方法
大家可以在MSDN看一下其派生類
(2)HtmlTextWriter 類
不得不了解的一個類,主要工作就是我們寫的標記字符和文本輸出
2.ASP.NET自定義控件之重寫方法
(1) 必須繼承Control類
(2) 重寫Control類的Render方法,這個是必須的,因為其他控件都繼承了Control 類類,所以幾乎所有控件都有這個方法
3.熟悉元數(shù)據(jù)
大家都知道ASP.NET控件屬性在編輯器上是分類的,如外觀,行為,布局等,每個屬性還給出了解釋
簡單的元數(shù)據(jù)就是起到這個作用,當然你也可以不加,但使用了元數(shù)據(jù)讓人感到有親切感,寫法如
下
[CategoryAttribute("Appearance")]
要使用元數(shù)據(jù),必須引用System.ComponentModel命名控件,一般你如果寫組件的話,不可能不用到這樣類庫。具體的MSDN上有所介紹。
一.輸出字符串
說多了沒意思,還是來演練吧。首先你得了解HTML。來看下面代碼,效果就是輸出HTML到客戶端
示例一
- using System;
- 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文件夾里,就可自動編譯,當然也可以創(chuàng)建web控件庫.
注意要繼承Control類,重寫Render方法,用HtmlTextWriter類的Write輸出HTML
使用控件
(1).需要先注冊一下
﹤%@ Register TagPrefix="custom" Namespace="CustomComponents" %﹥
(2) 然后就使用標簽輸出效果
﹤custom:CreditCardForm1 runat="server" ID="ccf" /﹥
下為效果圖
二.改善,加入屬性和元數(shù)據(jù)
可能上面做出的 控件毫無用處,但卻可以讓你熟悉一下步驟,上面的控件定的很死,沒有定義任何屬性,用處不大,下面來改造
我們來定義常用屬性,然后再輸出,這樣我們就可以修改控件的屬性了,
示例二
- using System;
- 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("獲取和設(shè)置信用卡類型")]
- [DefaultValueAttribute("信用卡類型")]
- [CategoryAttribute("Appearance")]
- public virtual string PaymentMethodText
- {
- get { return this.paymentMethodText; }
- set { this.paymentMethodText = value; }
- }
- [BrowsableAttribute(true)]
- [DescriptionAttribute("獲取或設(shè)置信用卡卡號")]
- [DefaultValueAttribute("信用卡卡號")]
- [CategoryAttribute("Appearance")]
- public virtual string CreditCardNoText
- {
- get { return this.creditCardNoText; }
- set { this.creditCardNoText = value; }
- }
- [BrowsableAttribute(true)]
- [DescriptionAttribute("獲取或設(shè)置信用卡持有者姓名")]
- [DefaultValueAttribute("信用卡持有者姓名")]
- [CategoryAttribute("Appearance")]
- public virtual string CardholderNameText
- {
- get { return this.cardholderNameText; }
- set { this.cardholderNameText = value; }
- }
- [BrowsableAttribute(true)]
- [DescriptionAttribute("獲取或設(shè)置***使用時間")]
- [DefaultValueAttribute("***使用時間")]
- [CategoryAttribute("Appearance")]
- public virtual string ExpirationDateText
- {
- get { return this.expirationDateText; }
- set { this.expirationDateText = value; }
- }
- [BrowsableAttribute(true)]
- [DescriptionAttribute("獲取或設(shè)置按鈕標簽")]
- [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);
- }
- }
- }
上面我們接觸到了元數(shù)據(jù)了,意思應該很好理解,為了測試元數(shù)據(jù)的作用,大家可以新建一個類庫項目,然后把寫的代碼放這個項目里面,接著web網(wǎng)站引用這個項目,成功生成以后,你會發(fā)現(xiàn)工具箱已經(jīng)自動幫你加上了這幾個控件
接著你要做的工作就是拖動你需要的控件,然后你會在屬性面板看到下圖
然后你再結(jié)合代碼中的元數(shù)據(jù),應該就知道大概意思了.(可以根據(jù)你的理解結(jié)合MSDN看)
三.再次改善,淘汰用Write方法以字符串的方式輸出HTML
接著我們繼續(xù)發(fā)現(xiàn)問題,我們發(fā)現(xiàn)我們除了定義幾個需要自己來修改的屬性外,還是要用來大量的字符串用來輸出HTML,而且容易輸錯.所以HtmlTextWriter類提供幾個有用的方法用來代替.
(1)AddStyleAttribute方法 為標簽添加樣式屬性
(2)AddAttribute方法 為標簽添加屬性
(3)RenderBeginTag 開始寫入標簽頭 如﹤table....﹥
(4)RenderEndTag 寫入標簽尾部,如﹤/table﹥
這里有幾點需要特別注意.
一.因為其定義方式跟我們平時定義方式不同,我們平時寫HTML時,是先寫標簽開頭,再寫標簽的屬性.如﹤table borderwidth="0"﹥,然而我們在使用上面幾個方法時,需要有先后順序,我們需要先定義標簽的屬性和樣式,然后再輸出標簽頭.
二.標簽頭和尾,需一一對應.可以理解為嵌套關(guān)系.***的理解方法就是輸出代碼后,查看源文件,再結(jié)合原來定義的代碼來看.
還是看代碼比較容易說明,由于CreditCardForm2已經(jīng)定義了我們需要的屬性,而我們現(xiàn)在要做的只是用標簽的形式來替代字符串的形式,所以只需要繼承CreditCardForm2類,重寫Render方法即可
示例三
- protected override void Render(HtmlTextWriter writer)
- {
- 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();
- }
實現(xiàn)的效果雖然一樣,但上面的代碼是不是漂亮很多,而且不容易輸錯.這也是所提倡的做法
四.未使用視圖狀態(tài)的后果
還是視圖狀態(tài),關(guān)于視圖狀態(tài)大家可以參考MSDN和相關(guān)文章
看以下的示例,還是CreditCardForm3這個控件
- if (!IsPostBack)
- {
- creditcardform.CardholderNameText = "Full Name";
- creditcardform.CreditCardNoText = "CreditCardNo";
- creditcardform.ExpirationDateText = "ExpirationDate";
- creditcardform.PaymentMethodText = "Payment Options";
- creditcardform.SubmitButtonText = "Send";
- }
***加載效果
點擊按鈕以后
五.使用視圖狀態(tài)改善效果
前提條件是你未禁用視圖狀態(tài)
繼承CreditCardForm3,改寫每個屬性
- public override string PaymentMethodText
- {
- 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; }
- }
以上全為個人見解,如有錯誤,希望大家指出.
ASP.NET控件開發(fā)基礎(chǔ)之自定義控件的了解就向大家介紹到這里,對于ASP.NET控件開發(fā)基礎(chǔ)在以后的文章中還會想大家慢慢介紹。