用Visual C#.NET編寫伺服器日期控制項

來源:互聯網
上載者:User
一、序言

  Visual C#.NET是微軟公司出品的一種新的程式設計語言(以下簡稱C#),它繼承了C語言的一些特性,也加入了一些新的元素。以前用過Delphi開發程式的人可能剛開始使用C#的時候,對其有一種似曾相識的感覺(至少包括我)。 是的,C#語言的創始人正是以前在Borland公司開發出Delphi語言的Anders Hejlsberg。在我開始使用C#開發程式時,就覺得它是一款很棒的開發Windows Form & Web程式的RAD工具。
在開發Web程式方面,C#的出現打破了以前的網頁開發模式,實現了與開發Windows

  Form程式一樣的所見即所得 (WYSIWYG)的功能。C#提供了一些常用的Web Form Control供開發人員使用,並且只需將控制項拖入頁面中即可,非常簡單。但有時這些控制項也不能滿足開發人員的需要,需要開發人員自己編寫使用者控制項(User Control)或自訂控制項(Custom Control)來滿足需求。在這裡,我將講解如何在C#中程式開發伺服器控制項。

  二、預備知識

  在C#中可以開發兩種伺服器控制項,一個是使用者控制項(User Control)和自訂控制項(Custom Control)。使用者控制項的本質與分頁檔(aspx檔案)差不多,是可被其它aspx頁面重複使用的HTML程式碼片段,當然它也包括後台代碼(Code-behind),尾碼名是ascx。所以在開發一些公用的靜態頁面時(例如頁頭,頁尾)經常用到,但它的缺點是不易繼承,不易分發,無法編譯成二進位代碼來進行部署。但是自訂控制項的功能就強大許多,它可以被編譯成二進位代碼(DLL檔案),可以被擴充、繼承、分發。就像Web Form Control一樣,其實它們每個控制項就是一個DLL檔案。

  開發使用者控制項比較簡單,就像編寫一個aspx頁面一樣,在這裡就不介紹了。本文對象是自訂控制項。伺服器控制項的基類是System.Web.UI.Control。如果要開發可視化的伺服器控制項,那我們需要從System.Web.UI.WebControls來繼承,否則從System.Web.UI.Control繼承。

  伺服器控制項在設計時以runat=”server”指令碼代碼嵌入到aspx檔案中來表示此控制項是在伺服器端啟動並執行。在伺服器控制項所在頁面提交回傳(PostBack)過程中是依靠ViewState(檢視狀態)來維護控制項狀態的。所以我們在設計伺服器控制項屬性時,其值應儲存在ViewState中。

  三、代碼編寫

  C#中有一個日曆控制項Calendar,但是現在我需要一個可以下拉的日曆控制項,並且初始時不顯示日曆,當我點擊下拉按鈕時才彈出,並且當選擇了日期,日曆會自動隱藏且選擇的日期值會顯示到相應的輸入框中。顯然Calendar控制項不能滿足我的需要,但是稍後我會在我的自訂控制項中用到它。

  首先建立項目,在項目類型中選擇Visual C#項目,在模板列表中選擇Web控制項陳列庫,輸入項目名稱AquaCalendar,然後選擇項目所在目錄,點擊【確定】按鈕。C#將會產生基本的架構代碼。將項目中的類檔案和類名改名為DatePicker(即日期控制項的類名)。由於DatePicker是可視化控制項,所以我們必須從System.Web.UI.WebControls繼承。並且它包括一個輸入框,一個按鈕和日曆控制項,需要在DatePicker類中聲明它們。像這種以多個伺服器控制群組合的控制項成為複合控制項。代碼如下,比較重要的方法和代碼在注釋中會加以說明:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Drawing;

namespace AquaCalendar
{
 [DefaultProperty("Text"), //在屬性工具箱中顯示的預設屬性
 ToolboxData("<{0}:DatePicker runat=server></{0}:DatePicker>")]
 public class DatePicker : System.Web.UI.WebControls.WebControl , IPostBackEventHandler
 {
  //選擇日期按鈕的預設樣式
  private const string _BUTTONDEFAULTSTYLE = "BORDER-RIGHT: gray 1px solid; BORDER-TOP: gray 1px solid; BORDER-LEFT: gray 1px solid; CURSOR: hand; BORDER-BOTTOM: gray 1px solid;";

  //按鈕預設文本

  private const string _BUTTONDEFAULTTEXT = "...";
  private System.Web.UI.WebControls.Calendar _Calendar;

  public override ControlCollection Controls
  {
   get
   {
    EnsureChildControls(); //確認子控制項集都已被建立
    return base.Controls;
   }
  }

  //建立子控制項(伺服器日曆控制項)

  protected override void CreateChildControls()
  {
   Controls.Clear();
   _Calendar = new Calendar();
   _Calendar.ID = MyCalendarID;
   _Calendar.SelectedDate = DateTime.Parse(Text);
   _Calendar.TitleFormat = TitleFormat.MonthYear;
   _Calendar.NextPrevFormat = NextPrevFormat.ShortMonth;
   _Calendar.CellSpacing = 0;
   _Calendar.Font.Size = FontUnit.Parse("9pt");
   _Calendar.Font.Name = "Verdana";
   _Calendar.SelectedDayStyle.BackColor = ColorTranslator.FromHtml("#333399");
   _Calendar.SelectedDayStyle.ForeColor = ColorTranslator.FromHtml("White");
   _Calendar.DayStyle.BackColor = ColorTranslator.FromHtml("#CCCCCC");
   _Calendar.TodayDayStyle.BackColor = ColorTranslator.FromHtml("#999999");
   _Calendar.TodayDayStyle.ForeColor = ColorTranslator.FromHtml("Aqua");
   _Calendar.DayHeaderStyle.Font.Size = FontUnit.Parse("8pt");
   _Calendar.DayHeaderStyle.Font.Bold = true;
   _Calendar.DayHeaderStyle.Height = Unit.Parse("8pt");
   _Calendar.DayHeaderStyle.ForeColor = ColorTranslator.FromHtml("#333333");
   _Calendar.NextPrevStyle.Font.Size = FontUnit.Parse("8pt");
   _Calendar.NextPrevStyle.Font.Bold = true;
   _Calendar.NextPrevStyle.ForeColor = ColorTranslator.FromHtml("White");
   _Calendar.TitleStyle.Font.Size = FontUnit.Parse("12pt");
   _Calendar.TitleStyle.Font.Bold = true;
   _Calendar.TitleStyle.Height = Unit.Parse("12pt");
   _Calendar.TitleStyle.ForeColor = ColorTranslator.FromHtml("White");
   _Calendar.TitleStyle.BackColor = ColorTranslator.FromHtml("#333399");
   _Calendar.OtherMonthDayStyle.ForeColor = ColorTranslator.FromHtml("#999999");
   _Calendar.NextPrevFormat = NextPrevFormat.CustomText;
   _Calendar.NextMonthText = "下月";
   _Calendar.PrevMonthText = "上月";
   _Calendar.Style.Add("display","none"); //預設不顯示下拉日曆控制項
   _Calendar.SelectionChanged += new EventHandler(_Calendar_SelectionChanged);
   this.Controls.Add(_Calendar);
  }
  [
   Category("Appearance"), //該屬性所屬類別,參見圖
   DefaultValue(""), //屬性預設值
   Description("設定該日期控制項的值。") //屬性的描述
  ]

  public string Text
  {
   get
   {
    EnsureChildControls();
    return (ViewState["Text"] == null)?System.DateTime.Today.ToString("yyyy-MM-dd"):ViewState["Text"].ToString();
   }
   set
   {
    EnsureChildControls();
    DateTime dt = System.DateTime.Today;
    try
    {
     dt = DateTime.Parse(value);
    }
    catch
    {
     throw new ArgumentOutOfRangeException("請輸入日期型字串(例如:1981-04-29)!");
    }

    ViewState["Text"] = DateFormat == CalendarEnum.LongDateTime?dt.ToString("yyyy-MM-dd"):dt.ToString("yyyy-M-d");
   }
  }

  //重載伺服器控制項的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:o.ToString();
   }
   set
   {
    EnsureChildControls();
    ViewState["ButtonSytle"] = value;
   }
  }

  [
   DefaultValue(CalendarEnum.LongDateTime),
  ]

  public CalendarEnum DateFormat
  {
   get
   {
    EnsureChildControls();
    object format = ViewState["DateFormat"];
    return format == null?CalendarEnum.LongDateTime:(CalendarEnum)format;
   }
   set
   {
    EnsureChildControls();
    ViewState["DateFormat"] = value;
    DateTime dt = DateTime.Parse(Text);
    Text=DateFormat == CalendarEnum.LongDateTime?dt.ToString("yyyy-MM-dd"):dt.ToString("yyyy-M-d");
   }
  }

  [
   Browsable(false),
   DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
  ]

  public string MyCalendarID //複合控制項ID
  {
   get
   {
    EnsureChildControls();
    return this.ClientID+"_MyCalendar";
   }
  }

  [
   Browsable(false),
   DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
  ]

  public string MyCalendarName //複合控制項名稱
  {
   get
   {
    EnsureChildControls();
    return this.UniqueID+":MyCalendar";
   }
  }

  [
   Browsable(false),
   DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
  ]

  public string DatePickerInputID //複合控制項中輸入框的ID
  {
   get
   {
    EnsureChildControls();
    return this.ClientID+"_DateInput";
   }
  }

  [
   Browsable(false),
   DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
  ]

  public string DatePickerInputName //複合控制項中輸入框的名稱
  {
   get
   {
    EnsureChildControls();
    return this.UniqueID+":DateInput";
   }
  }

  [
   Browsable(false),
   DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
  ]

  public string DatePickerButtonID //複合控制項中按鈕的ID
  {
   get
   {
    EnsureChildControls();
    return this.ClientID+"_DateButton";
   }
  }

  [
   Browsable(false),
   DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
  ]

  public string DatePickerButtonName //複合控制項中按鈕的名稱
  {
   get
   {
    EnsureChildControls();
    return this.UniqueID+":DateButton";
   }
  }

  public string ButtonText
  {
   get
   {
    EnsureChildControls();
    return ViewState["ButtonText"] == null?_BUTTONDEFAULTTEXT:(string)ViewState["ButtonText"];
   }
   set
   {
    EnsureChildControls();
    ViewState["ButtonText"] = value;
   }
  }

  /// <summary>
  /// 將此控制項呈現給指定的輸出參數。
  /// </summary>
  /// <param name="output"> 要寫出到的 HTML 編寫器 </param>

  protected override void Render(HtmlTextWriter output)
  {
   //在頁面中輸出控制項時,產生一個表格(二行二列),以下是表格的樣式
   output.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "0");
   output.AddAttribute(HtmlTextWriterAttribute.Border, "0");
   output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "0");

   output.AddStyleAttribute("LEFT", this.Style["LEFT"]);
   output.AddStyleAttribute("TOP", this.Style["TOP"]);
   output.AddStyleAttribute("POSITION", "absolute");

   if (Width != Unit.Empty)
   {
    output.AddStyleAttribute(HtmlTextWriterStyle.Width, Width.ToString());
   }
   else
   {
    output.AddStyleAttribute(HtmlTextWriterStyle.Width, "200px");
   }

   output.RenderBeginTag(HtmlTextWriterTag.Table); //輸出表格
   output.RenderBeginTag(HtmlTextWriterTag.Tr); //表格第一行
   output.AddAttribute(HtmlTextWriterAttribute.Width, "90%");
   output.RenderBeginTag(HtmlTextWriterTag.Td);

   //以下是第一行第一列中文字框的屬性及其樣式設定

   if (!Enabled)
   {
    output.AddAttribute(HtmlTextWriterAttribute.ReadOnly, "true");
   }

   output.AddAttribute(HtmlTextWriterAttribute.Type, "Text");
   output.AddAttribute(HtmlTextWriterAttribute.Id, DatePickerInputID);
   output.AddAttribute(HtmlTextWriterAttribute.Name, DatePickerInputName);
   output.AddAttribute(HtmlTextWriterAttribute.Value, Text);
   output.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%");
   output.AddStyleAttribute(HtmlTextWriterStyle.Height, "100%");
   output.AddStyleAttribute(HtmlTextWriterStyle.FontFamily, Font.Name);
   output.AddStyleAttribute(HtmlTextWriterStyle.FontSize, Font.Size.ToString());
   output.AddStyleAttribute(HtmlTextWriterStyle.FontWeight, Font.Bold?"bold":"");
   output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, ColorTranslator.ToHtml(BackColor));
   output.AddStyleAttribute(HtmlTextWriterStyle.Color, ColorTranslator.ToHtml(ForeColor));
   output.RenderBeginTag(HtmlTextWriterTag.Input); //輸出文字框
   output.RenderEndTag();
   output.RenderEndTag();
   output.AddAttribute(HtmlTextWriterAttribute.Width, "*");
   output.RenderBeginTag(HtmlTextWriterTag.Td);

   //以下是第一行第二列中按鈕的屬性及其樣式設定

   if (!Enabled)
   {
    output.AddAttribute(HtmlTextWriterAttribute.Disabled, "true");
   }

   output.AddAttribute(HtmlTextWriterAttribute.Type, "Submit");
   output.AddAttribute(HtmlTextWriterAttribute.Id, DatePickerButtonID);
   output.AddAttribute(HtmlTextWriterAttribute.Name, DatePickerButtonName);
   output.AddAttribute(HtmlTextWriterAttribute.Value, ButtonText);
   output.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%");
   output.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.GetPostBackEventReference(this)); //點擊按鈕時需要回傳伺服器來觸發後面的OnClick事件

   output.AddAttribute(HtmlTextWriterAttribute.Style, ButtonStyle);
   output.RenderBeginTag(HtmlTextWriterTag.Input); //輸出按鈕
   output.RenderEndTag();
   output.RenderEndTag();

   output.RenderEndTag();
   output.RenderBeginTag(HtmlTextWriterTag.Tr);
   output.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");
   output.RenderBeginTag(HtmlTextWriterTag.Td);
   _Calendar.RenderControl(output); //將日曆子控制項輸出
   output.RenderEndTag();
   output.RenderEndTag();
   output.RenderEndTag();
  }

  //複合控制項必須繼承IpostBackEventHandler介面,才能繼承RaisePostBackEvent事件

  public void RaisePostBackEvent(string eventArgument)
  {
   OnClick(EventArgs.Empty);
  }

  protected virtual void OnClick(EventArgs e)
  {
   //點擊選擇日期按鈕時,如果日曆子控制項沒有顯示則顯示出來並將文字框的值賦值給日曆子控制項
   if (_Calendar.Attributes["display"] != "")
   {
    _Calendar.SelectedDate = DateTime.Parse(Text);
    _Calendar.Style.Add("display","");
   }
  }

  //複合控制項中的日曆控制項日期變化事件

  private void _Calendar_SelectionChanged(object sender, EventArgs e)
  {
   //當選擇的日期變化時,將所選日期賦值給文字框並將日曆子控制項隱藏
   Text = _Calendar.SelectedDate.ToString();
   _Calendar.Style.Add("display","none");
  }
 }
}

  在上面的代碼中,需要注意以下幾點:

  ·如果你想將此控制項的某些屬性供重載,則在聲明屬性前加上virtual關鍵字;

  ·在頁面輸出此控制項時(即在Render事件中),是先定義子控制項的樣式或屬性,然後再產生子控制項;

  ·在隱藏日曆子控制項時,建議不要使用Visible屬性來顯示/隱藏,使用Visible=false隱藏時伺服器端將不會將日曆控制項HTML代碼發送給用戶端,會導致複合控制項裝載日曆控制項的表格會空白一塊出來,影響頁面的布局。所以使用樣式display=none設定來使日曆控制項在用戶端隱藏,但是HTML代碼依然存在於頁面中;

  四、結束語

  在編寫伺服器控制項時,需要一定的HTML語言基礎,也要清楚.NET程式的請求處理方式。伺服器控制項封裝了用戶端行為及邏輯判斷,無需開發人員添加更多代碼。當然,有些地方使用伺服器控制項可以帶來方便,但是也增加了伺服器的負荷。有時適當的結合javascript使一些代碼在用戶端運行,可提高WEB應用程式效率。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.