65.9K
CodeProject 正在变化。 阅读更多。
Home

支持语言和不同日期格式的日期控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.14/5 (10投票s)

2005年5月13日

4分钟阅读

viewsIcon

99576

downloadIcon

713

使用 .NET 的 System.Globalization 类来检索外国语言的月份名称,以及 DateTimeFormatInfo 来确保您的日期格式正确。

引言

互联网上有很多日期控件,包括 CodeProject 上的许多。然而,很少有控件能够利用 .NET 的 System.Globalization 类来检索外语月份的名称。从南非荷兰语到越南语的月份名称,无需了解所说的语言即可实现。此外,我还增加了处理任何我选择的日期格式的可能性。此控件可以很好地处理美国或欧洲的日期格式。该控件还支持 Visual Studio 设计器。

背景

System.Globalization 命名空间包含定义与区域设置相关信息的类,包括语言、国家/地区、使用的日历以及日期、货币和数字的格式模式。

我使用了 CodeProject 上的 David Truxall 的控件 作为该控件的模板,并添加了以下功能:

属性

属性 默认值 描述
YearsForward 0 (可选)一个整数,用于设置控件从当前年份开始显示的未来年份数。
YearsBack 0 (可选)一个整数,用于设置控件从当前年份开始显示的过去年份数。
文化 (可选)一个 string,与 Culture Name 相同,用于显示月份名称。例如,en-gb es-ES。有关完整列表,请参阅 MSDN。如果未设置,则使用服务器的区域代码。

- 这不会影响控件的值。
MonthFormat MMMM (可选)一个 string,用于设置控件中的月份文本。

例如 MMM、MMMM、MM。

- 这不会影响控件的值。
DateFormat 默认使用服务器上的格式 一个 string,用于设置输出日期值格式。

例如,dd/MM/yyyy MM-dd-yyyy yyyyMMdd
一个用于设置 date 的值。

* 请注意,如果您使用 dd/MM/yyyy,请确保值设置为双位数,例如 02/04/2005 是有效的,而 2/4/2005 是无效的。
SelectCurrentDate true 一个布尔值,用于在未指定值时将值设置为当前日期。

使用示例

<%@ Register TagPrefix="cc1" 
  Namespace="i386.UI" Assembly="i386.UI" %>

德语,显示短月份文本,未来 10 年,比当前年份早 2 年

<cc1:dropdowndatetime  id="DropDownDateTime1" runat="server" YearsForward="2" 
   YearsBack="10" Culture="de-DE"   SelectCurrentDate="False" MonthFormat="MMM">
</cc1:dropdowndatetime>

使用 date 进行美国日期格式化

<cc1:dropdowndatetime id="Dropdowndatetime4" runat="server" 
  dateFormat="MM/dd/yyyy" Value="11/02/2005">
</cc1:dropdowndatetime>

YearsForwardYearsBack 属性可以为负值,这会控制范围和顺序。

YearsForward YearsBack 显示的年份
-11 20 1985 ... 1994
11 -20 1994 ... 1985
11 20 1985 ... 2016

控件的工作原理

首先,DateFormat 默认设置为服务器当前使用的格式,除非设置了 DateFormat 属性。

private string _DateFormat= 
      System.Threading.Thread.CurrentThread.
             CurrentCulture.DateTimeFormat.ShortDatePattern;        
public string Value 
{
    get 
    {
        string s = (string)ViewState["Value"];
        if(s == null) return String.Empty;
        else return s;
    }                
    set 
    {
        this.SetSelected(value);
        ViewState["Value"] = value;
    }
}


private void SetSelected(string StoredValue)
{
    DateTimeFormatInfo formatInfo = 
                         new DateTimeFormatInfo();
    formatInfo.FullDateTimePattern = DateFormat;
    DateTime dt = DateTime.ParseExact(StoredValue,
                                DateFormat,formatInfo);    
    SelectedDay  = dt.Day;
    SelectedMonth = dt.Month;
    SelectedYear = dt.Year;    
}

该控件实现 IPostBackDataHandler 来管理控件值在 PostBack 时发生更改时的重置。这与 David Truxall 的相同,不同之处在于构建 postCollectionValue 属性。

bool IPostBackDataHandler.LoadPostData(string postDataKey, 
     System.Collections.Specialized.NameValueCollection postCollection)
{
    ....
    ....                
    if(this.SelectedDay == -1 && this.SelectedMonth == -1 && 
                                         this.SelectedYear == -1)
        this.Value = "";
    else
    {
        // Build a DateTime string based on the DateFormat
        DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
        formatInfo.FullDateTimePattern = DateFormat;
        DateTime dt = new DateTime(this.SelectedYear, 
                           this.SelectedMonth, this.SelectedDay);
        this.Value = dt.ToString(DateFormat,formatInfo);
    }
}

构建子控件

SelectCurrentDate 设置为 true(默认)并且控件的 Value 为空时,我们将控件设置为当前日期。我们使用 DateTimeFormatInfoDateFormat 将日期正确格式化为 string 以用于 Value 属性。如果 SelectCurrentDate 设置为 false,则控件设置为年份下拉框中列出的第一年的 1 月 1 日。我们使用 JavaScript 来限制闰年的天数,并保持 Value 输入框的更新。Value 由客户端和服务器值保持最新。

protected override void CreateChildControls()
{
    DateTime dt = DateTime.Today;
    // Use CurrentDate if Value is empty and 
    // SelectCurrentDate is true.
    if (SelectCurrentDate && this.Value=="")
    {
        // Use Current Date
        SelectedDay  = dt.Day;
        SelectedMonth = dt.Month;
        SelectedYear = dt.Year;
        DateTimeFormatInfo formatInfo = 
                               new DateTimeFormatInfo();
        formatInfo.FullDateTimePattern = DateFormat;
        this.Value = dt.ToString(DateFormat,formatInfo);
    }

    // Days
    DropDownList ddlboxDay = new DropDownList();
    ddlboxDay.ID ="Day";
    ddlboxDay.Attributes.Add("onchange",
      "ChangeOptionDays('" + this.ClientID +"',
                              '" + DateFormat + "');");
    for (int nDay = 1; nDay<32; nDay++)
                  ddlboxDay.Items.Add(nDay.ToString());

    
    // So we can restore the Culture later
    CultureInfo ExistingCulture = 
      System.Threading.Thread.CurrentThread.CurrentCulture; 
    // Culture - changes language of months    
    if (Culture!=null)    
      System.Threading.Thread.CurrentThread.CurrentCulture = 
                  new System.Globalization.CultureInfo(Culture);    

    // Months
    DropDownList ddlboxMonth = new DropDownList();
    ddlboxMonth.ID ="Month";
    ddlboxMonth.Attributes.Add("onchange",
      "ChangeOptionDays('" + this.ClientID +"',
                             '" + DateFormat + "');");
    for ( int nMonth=1; nMonth<=12; nMonth++)
    { 
        DateTime MonthDate = new DateTime(2000,nMonth,1);
        ddlboxMonth.Items.Add(new 
              ListItem(MonthDate.ToString(this.MonthFormat),
                                            nMonth.ToString()));
    }
     // Restore 
    System.Threading.Thread.CurrentThread.CurrentCulture = 
                                              ExistingCulture;


    // Years (Forward and Back properties)    
    DropDownList ddlboxYear = new DropDownList();
    ddlboxYear.ID ="Year";
    ddlboxYear.Attributes.Add("onchange",
               "ChangeOptionDays('" + this.ClientID +"',
                                      '" + DateFormat + "');");
    ddlboxYear.ID ="Year";
      if (YearsBack>=0)
      {
        for (int nYear = -YearsBack; nYear<=YearsForward; nYear++)
        {
            int ddlYear =dt.Year+nYear;
            ddlboxYear.Items.Add(ddlYear.ToString());
        }
      }
      else
      {
        for (int nYear = YearsForward; nYear<=-YearsBack; nYear++)
        {
            int ddlYear =dt.Year-nYear;
            ddlboxYear.Items.Add(ddlYear.ToString());
        }
      }

    // Select the DropDownList for the year
    if (SelectedYear>0)
    {
        // See if the year is in the list.
        if (ddlboxYear.Items.FindByValue(SelectedYear.ToString())!=null) 
        {
           ddlboxYear.Items.FindByValue(SelectedYear.ToString()).Selected = 
                                                                        true;
        }
    }
    if (SelectedMonth>0)    
      ddlboxMonth.Items.FindByValue(SelectedMonth.ToString()).Selected = true;
    if (SelectedDay>0)    
      ddlboxDay.Items.FindByValue(SelectedDay.ToString()).Selected = true;

    // Add Child Control
    Controls.Add(ddlboxDay);
    Controls.Add(ddlboxMonth);
    Controls.Add(ddlboxYear);

调试模式

用于检查控件的运行情况。DebugMode 输出 ValueViewStatesCultureInfoDateFormat。要启用 DebugMode,请使用 DebugMode="true"

<cc1:dropdowndatetime DebugMode=true id="DropDownDateTime1" runat="server">
</cc1:dropdowndatetime>

浏览器兼容性

这只是我测试过的浏览器列表中的一小部分。我的电脑上没有安装 Netscape。

浏览器 操作系统下
Safari 1.0.3
Mac System 9+ 完全支持
Netscape 4.77 Mac System 10.2.8
Opera 6.0.3 Mac System 10.2.8 完全支持
Internet Explorer 5.1, 5.2 Mac System 9+ 完全支持
Firefox 1.x Windows XP 完全支持
Internet Explorer 4.0+ Windows XP 完全支持
Netscape ?? Windows ??

Internet Explorer 3.0 需要使用服务器验证。如果某个浏览器无法正常工作,请告知我。

JavaScript 支持

从调试模式中,您可能会注意到隐藏的输入框。此输入框可以在 PostBack 到服务器之前在 JavaScript 中使用。

更新、版本和错误修复

  • 2005 年 5 月 18 日,版本 0.2
    • 添加并修复了 YearsForwardYearsBack 属性的负值。
    • 支持旧版 JavaScript 浏览器。

未来增强功能

  • 支持和测试使用服务器验证的旧版、无 JavaScript 或禁用 JavaScript 的浏览器。
  • EnableSetDate 属性尚未完成。此功能通过复选框启用/禁用日期框,并允许空白日期。
  • 日期和闰年的服务器验证。源代码中包含一个 DateTimeValidator
  • 另一个功能是支持 Value 的年份超出 YearsForwardYearsBack 属性范围。
  • 时间支持。

欢迎评论或自行添加功能。如果您对该页面的评分较低,请在下方的论坛中留言。

© . All rights reserved.