一序言
Visual 是微軟公司出品的一種新的編程語言(以下簡稱C#)它繼承了C語言的一些特性也加入了一些新的元素以前用過Delphi開發程序的人可能剛開始使用C#的時候對其有一種似曾相識的感覺(至少包括我)是的C#語言的創始人正是以前在Borland公司開發出Delphi語言的Anders Hejlsberg在我開始使用C#開發程序時就覺得它是一款很棒的開發Windows Form & Web程序的RAD工具
在開發Web程序方面C#的出現打破了以前的網頁開發模式實現了與開發Windows
Form程序一樣的所見即所得的功能C#提供了一些常用的Web Form Control供開發人員使用並且只需將控件拖入頁面中即可非常簡單但有時這些控件也不能滿足開發人員的需要需要開發人員自己編寫用戶控件(User Control)或自定義控件(Custom Control)來滿足需求在這裡我將講解如何在C#中開發服務器控件
二預備知識
在C#中可以開發兩種服務器控件一個是用戶控件(User Control)和自定義控件(Custom Control)用戶控件的本質與頁面文件(ASPx文件)差不多是可被其它aspx頁面重復使用的HTML代碼段當然它也包括後台代碼(Codebehind)後綴名是ascx所以在開發一些公用的靜態頁面時(例如頁頭頁腳)經常用到但它的缺點是不易繼承不易分發無法編譯成二進制代碼來進行部署但是自定義控件的功能就強大許多它可以被編譯成二進制代碼(DLL文件)可以被擴展繼承分發就像Web Form Control一樣其實它們每個控件就是一個DLL文件
開發用戶控件比較簡單就像編寫一個aspx頁面一樣在這裡就不介紹了本文對象是自定義控件服務器控件的基類是SystemWebUIControl如果要開發可視化的服務器控件那我們需要從SystemWebUIWebControls來繼承否則從SystemWebUIControl繼承
服務器控件在設計時以runat=server腳本代碼嵌入到aspx文件中來表示此控件是在服務器端運行的在服務器控件所在頁面提交回傳(PostBack)過程中是依靠ViewState(視圖狀態)來維護控件狀態的所以我們在設計服務器控件屬性時其值應保存在ViewState中
三代碼編寫
C#中有一個日歷控件Calendar但是現在我需要一個可以下拉的日歷控件並且初始時不顯示日歷當我點擊下拉按鈕時才彈出並且當選擇了日期日歷會自動隱藏且選擇的日期值會顯示到相應的輸入框中顯然Calendar控件不能滿足我的需要但是稍後我會在我的自定義控件中用到它
首先新建項目在項目類型中選擇Visual C#項目在模板列表中選擇Web控件庫輸入項目名稱AquaCalendar然後選擇項目所在目錄點擊【確定】按鈕C#將會生成基本的框架代碼將項目中的類文件和類名改名為DatePicker(即日期控件的類名)由於DatePicker是可視化控件所以我們必須從SystemWebUIWebControls繼承並且它包括一個輸入框一個按鈕和日歷控件需要在DatePicker類中聲明它們像這種以多個服務器控件組合的控件成為復合控件代碼如下比較重要的方法和代碼在注釋中會加以說明
using System;
using SystemWebUI;
using SystemWebUIWebControls;
using SystemComponentModel;
using SystemDrawing;
namespace AquaCalendar
{
[DefaultProperty(Text)
//在屬性工具箱中顯示的默認屬性
ToolboxData(<{}:DatePicker runat=server>)]
public class DatePicker :
SystemWebUIWebControlsWebControl
IPostBackEventHandler
{
//選擇日期按鈕的默認樣式
private const string _BUTTONDEFAULTSTYLE = BORDERRIGHT: gray px solid; BORDERTOP: gray px solid; BORDERLEFT: gray px solid; CURSOR: hand; BORDERBOTTOM: gray px solid;;
//按鈕默認文本
private const string _BUTTONDEFAULTTEXT = ;
private SystemWebUIWebControlsCalendar _Calendar;
public override ControlCollection Controls
{
get
{
EnsureChildControls(); //確認子控件集都已被創建
return baseControls;
}
}
//創建子控件(服務器日歷控件)
protected override void CreateChildControls()
{
ControlsClear();
_Calendar = new Calendar();
_CalendarID = MyCalendarID;
_CalendarSelectedDate = DateTimeParse(Text);
_CalendarTitleFormat = TitleFormatMonthYear;
_CalendarNextPrevFormat = NextPrevFormatShortMonth;
_CalendarCellSpacing = ;
_CalendarFontSize = FontUnitParse(pt);
_CalendarFontName = Verdana;
_CalendarSelectedDayStyleBackColor = ColorTranslatorFromHtml(#);
_CalendarSelectedDayStyleForeColor = ColorTranslatorFromHtml(White);
_CalendarDayStyleBackColor = ColorTranslatorFromHtml(#CCCCCC);
_CalendarTodayDayStyleBackColor = ColorTranslatorFromHtml(#);
_CalendarTodayDayStyleForeColor = ColorTranslatorFromHtml(Aqua);
_CalendarDayHeaderStyleFontSize = FontUnitParse(pt);
_CalendarDayHeaderStyleFontBold = true;
_CalendarDayHeaderStyleHeight = UnitParse(pt);
_CalendarDayHeaderStyleForeColor = ColorTranslatorFromHtml(#);
_CalendarNextPrevStyleFontSize = FontUnitParse(pt);
_CalendarNextPrevStyleFontBold = true;
_CalendarNextPrevStyleForeColor = ColorTranslatorFromHtml(White);
_CalendarTitleStyleFontSize = FontUnitParse(pt);
_CalendarTitleStyleFontBold = true;
_CalendarTitleStyleHeight = UnitParse(pt);
_CalendarTitleStyleForeColor = ColorTranslatorFromHtml(White);
_CalendarTitleStyleBackColor = ColorTranslatorFromHtml(#);
_CalendarOtherMonthDayStyleForeColor = ColorTranslatorFromHtml(#);
_CalendarNextPrevFormat = NextPrevFormatCustomText;
_CalendarNextMonthText = 下月;
_CalendarPrevMonthText = 上月;
_CalendarStyleAdd(displaynone); //默認不顯示下拉日歷控件
_CalendarSelectionChanged += new EventHandler(_Calendar_SelectionChanged);
thisControlsAdd(_Calendar);
}
[
Category(Appearance) //該屬性所屬類別參見圖
DefaultValue() //屬性默認值
Description(設置該日期控件的值) //屬性的描述
]
public string Text
{
get
{
EnsureChildControls();
return (ViewState[Text] == null)?SystemDateTimeTodayToString(yyyyMMdd):ViewState[Text]ToString();
}
set
{
EnsureChildControls();
DateTime dt = SystemDateTimeToday;
try
{
dt = DateTimeParse(value);
}
catch
{
throw new ArgumentOutOfRangeException(請輸入日期型字符串(例如)!);
}
ViewState[Text] = DateFormat == CalendarEnumLongDateTime?dtToString(yyyyMMdd):dtToString(yyyyMd);
}
}
//重載服務器控件的Enabled屬性將選擇日期按鈕變灰(禁用)
public override bool Enabled
{
get
{
EnsureChildControls();
return ViewState[Enabled] == null?true:(bool)ViewState[Enabled];
}
set
{
EnsureChildControls();
ViewState[Enabled] = value;
}
}
public string ButtonStyle
{
get
{
EnsureChildControls();
object o = ViewState[ButtonSytle];
return (o == null)?_BUTTONDEFAULTSTYLE:oToString();
}
set
{
EnsureChildControls();
ViewState[ButtonSytle] = value;
}
}
[
DefaultValue(CalendarEnumLongDateTime)
]
public CalendarEnum DateFormat
{
get
{
EnsureChildControls();
object format = ViewState[DateFormat];
return format == null?CalendarEnumLongDateTime:(CalendarEnum)format;
}
set
{
EnsureChildControls();
ViewState[DateFormat] = value;
DateTime dt = DateTimeParse(Text);
Text=DateFormat == CalendarEnumLongDateTime?dtToString(yyyyMMdd):dtToString(yyyyMd);
}
}
[
Browsable(false)
DesignerSerializationVisibility(DesignerSerializationVisibilityHidden)
]
public string MyCalendarID //復合控件ID
{
get
{
EnsureChildControls();
return thisClientID+_MyCalendar;
}
}
[
Browsable(false)
DesignerSerializationVisibility(DesignerSerializationVisibilityHidden)
]
public string MyCalendarName //復合控件名稱
{
get
{
EnsureChildControls();
return thisUniqueID+:MyCalendar;
}
}
[
Browsable(false)
DesignerSerializationVisibility(DesignerSerializationVisibilityHidden)
]
public string DatePickerInputID //復合控件中輸入框的ID
{
get
{
EnsureChildControls();
return thisClientID+_DateInput;
}
}
[
Browsable(false)
DesignerSerializationVisibility(DesignerSerializationVisibilityHidden)
]
public string DatePickerInputName //復合控件中輸入框的名稱
{
get
{
EnsureChildControls();
return thisUniqueID+:DateInput;
}
}
[
Browsable(false)
DesignerSerializationVisibility(DesignerSerializationVisibilityHidden)
]
public string DatePickerButtonID //復合控件中按鈕的ID
{
get
{
EnsureChildControls();
return thisClientID+_DateButton;
}
}
[
Browsable(false)
DesignerSerializationVisibility(DesignerSerializationVisibilityHidden)
]
public string DatePickerButtonName //復合控件中按鈕的名稱
{
get
{
EnsureChildControls();
return thisUniqueID+:DateButton;
}
}
public string ButtonText
{
get
{
EnsureChildControls();
return ViewState[ButtonText] == null?_BUTTONDEFAULTTEXT:(string)ViewState[ButtonText];
}
set
{
EnsureChildControls();
ViewState[ButtonText] = value;
}
}
///
/// 將此控件呈現給指定的輸出參數
///
/// 要寫出到的 HTML 編寫器
protected override void Render(HtmlTextWriter output)
{
//在頁面中輸出控件時產生一個表格(二行二列)以下是表格的樣式
outputAddAttribute(HtmlTextWriterAttributeCellspacing );
outputAddAttribute(HtmlTextWriterAttributeBorder );
outputAddAttribute(HtmlTextWriterAttributeCellpadding );
outputAddStyleAttribute(LEFT thisStyle[LEFT]);
outputAddStyleAttribute(TOP thisStyle[TOP]);
outputAddStyleAttribute(POSITION absolute);
if (Width != UnitEmpty)
{
outputAddStyleAttribute(HtmlTextWriterStyleWidth WidthToString());
}
else
{
outputAddStyleAttribute(HtmlTextWriterStyleWidth px);
}
outputRenderBeginTag(HtmlTextWriterTagTable); //輸出表格
outputRenderBeginTag(HtmlTextWriterTagTr); //表格第一行
outputAddAttribute(HtmlTextWriterAttributeWidth %);
outputRenderBeginTag(HtmlTextWriterTagTd);
//以下是第一行第一列中文本框的屬性及其樣式設置
if (!Enabled)
{
outputAddAttribute(HtmlTextWriterAttributeReadOnly true);
}
outputAddAttribute(HtmlTextWriterAttributeType Text);
outputAddAttribute(HtmlTextWriterAttributeId DatePickerInputID);
outputAddAttribute(HtmlTextWriterAttributeName DatePickerInputName);
outputAddAttribute(HtmlTextWriterAttributeValue Text);
outputAddStyleAttribute(HtmlTextWriterStyleWidth %);
outputAddStyleAttribute(HtmlTextWriterStyleHeight %);
outputAddStyleAttribute(HtmlTextWriterStyleFontFamily FontName);
outputAddStyleAttribute(HtmlTextWriterStyleFontSize FontSizeToString());
outputAddStyleAttribute(HtmlTextWriterStyleFontWeight FontBold?bold:);
outputAddStyleAttribute(HtmlTextWriterStyleBackgroundColor ColorTranslatorToHtml(BackColor));
outputAddStyleAttribute(HtmlTextWriterStyleColor ColorTranslatorToHtml(ForeColor));
outputRenderBeginTag(HtmlTextWriterTagInput); //輸出文本框
outputRenderEndTag();
outputRenderEndTag();
outputAddAttribute(HtmlTextWriterAttributeWidth *);
outputRenderBeginTag(HtmlTextWriterTagTd);
//以下是第一行第二列中按鈕的屬性及其樣式設置
if (!Enabled)
{
outputAddAttribute(HtmlTextWriterAttributeDisabled true);
}
outputAddAttribute(HtmlTextWriterAttributeType Submit);
outputAddAttribute(HtmlTextWriterAttributeId DatePickerButtonID);
outputAddAttribute(HtmlTextWriterAttributeName DatePickerButtonName);
outputAddAttribute(HtmlTextWriterAttributeValue ButtonText);
outputAddStyleAttribute(HtmlTextWriterStyleWidth %);
outputAddAttribute(HtmlTextWriterAttributeOnclick PageGetPostBackEventReference(this)); //點擊按鈕時需要回傳服務器來觸發後面的OnClick事件
outputAddAttribute(HtmlTextWriterAttributeStyle ButtonStyle);
outputRenderBeginTag(HtmlTextWriterTagInput); //輸出按鈕
outputRenderEndTag();
outputRenderEndTag();
outputRenderEndTag();
outputRenderBeginTag(HtmlTextWriterTagTr);
outputAddAttribute(HtmlTextWriterAttributeColspan );
outputRenderBeginTag(HtmlTextWriterTagTd);
_CalendarRenderControl(output); //將日歷子控件輸出
outputRenderEndTag();
outputRenderEndTag();
outputRenderEndTag();
}
//復合控件必須繼承IpostBackEventHandler接口才能繼承RaisePostBackEvent事件
public void RaisePostBackEvent(string eventArgument)
{
OnClick(EventArgsEmpty);
}
protected virtual void OnClick(EventArgs e)
{
//點擊選擇日期按鈕時如果日歷子控件沒有顯示則顯示出來並將文本框的值賦值給日歷子控件
if (_CalendarAttributes[display] != )
{
_CalendarSelectedDate = DateTimeParse(Text);
_CalendarStyleAdd(display);
}
}
//復合控件中的日歷控件日期變化事件
private void _Calendar_SelectionChanged(object sender EventArgs e)
{
//當選擇的日期變化時將所選日期賦值給文本框並將日歷子控件隱藏
Text = _CalendarSelectedDateToString();
_CalendarStyleAdd(displaynone);
}
}
}
在上面的代碼中需要注意以下幾點
·如果你想將此控件的某些屬性供重載則在聲明屬性前加上virtual關鍵字
·在頁面輸出此控件時(即在Render事件中)是先定義子控件的樣式或屬性然後再產生子控件
·在隱藏日歷子控件時建議不要使用Visible屬性來顯示/隱藏使用Visible=false隱藏時服務器端將不會將日歷控件HTML代碼發送給客戶端會導致復合控件裝載日歷控件的表格會空白一塊出來影響頁面的布局所以使用樣式display=none設置來使日歷控件在客戶端隱藏但是HTML代碼依然存在於頁面中
四結束語
在編寫服務器控件時需要一定的HTML語言基礎也要清楚NET程序的請求處理方式服務器控件封裝了客戶端行為及邏輯判斷無需開發者添加更多代碼當然有些地方使用服務器控件可以帶來方便但是也增加了服務器的負荷有時適當的結合JavaScript使一些代碼在客戶端運行可提高WEB應用程序效率
From:http://tw.wingwit.com/Article/program/net/201311/13736.html