BetterCalendar WebControl

分享于 

20分钟阅读

Web开发

  繁體

Sample Image - BetterCalendar.gif

介绍

BetterCalendar 是自 System.Web.UI.WebControls.Calendar 派生的自定义控件。 它旨在纠正 Calendar 控件的一些问题,并添加一些额外的功能。

背景

Calendar 控件非常有用,但它有几个 Bug 和缺点:

  • 仅使用样式表( 例如,将类名称分配给不同日历样式元素上的CssClass 属性) 设置日历的外观是不可能的。 这是因为控件嵌入了 inline 样式 默认样式属性时许多元素的属性。

    例如一天单元格的HTML可能看起来像:

    <tdclass="calendarDay"align="Center"style="width:12%;"><ahref="javascript:__doPostBack('Calendar1','1566')"style="color:Black">15</a></td>

    在这里,颜色的设置 样式 属性将覆盖 calendarDay 类中的任何颜色设置。

  • 可以根据特定条件为一天定义不同的样式- 通过 DayStyle , WeekendDayStyle , OtherMonthDayStyle , TodayDayStyleSelectedDayStyle 属性- 仅在可以应用多个样式类的情况下指定一个样式类。

    换句话说,如果今天的日期在一周结束,并且在控件上选择了日期,则 SelectedDayStyle 样式优先:

    <tdclass="selectedDay_style"...>

    由于一个HTML元素可能被分配多个类名 属性,则可以包括所有适用的样式类,如下所示:

    <tdclass="day_style weekendDay_style todayDay_style selectedDay_style"...>

    这将让你完全控制它通过样式表出现的方式。

  • 使用 DayRender 事件,可以控制哪些天是可选的,哪些是不可选的。 但是,当周或者月选择器处于活动状态时,所选的周或者月中的所有天都包含在选择中。 可以使用 SelectionChanged 事件手动删除这些日期,但这两次执行相同的工作。

  • 最后,对下个月和上个月的导航控件没有限制。 通过 VisibleMonthChanged 事件可以在语法上防止月外查看月份,但是下一个和上一个链接总是在控件上呈现。

BetterCalendar 控件解决这些问题。

使用代码

控件打包在类库中,命名空间 BrainJar.Web.UI.WebControls 只包含一个类,BetterCalendar

在 Visual Studio 网络项目中,你可以简单地添加对 BrainJar.Web. UI.WebControls.dll 文件的引用。 你可以在HTML视图中编辑你的网页表单并添加适当 @ register 指令和标记。below ( 注意包含外部样式表) 显示一个典型示例。

<%@Pagelanguage="c#"Codebehind="WebForm2.aspx.cs"AutoEventWireup="false"Inherits="Demo.WebForm2"%><%@RegisterTagPrefix="BrainJar"Namespace="BrainJar.Web.UI.WebControls"Assembly="BrainJar.Web.UI.WebControls"%><!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.0Transitional//EN"><HTML><HEAD><title>WebForm1</title><metaname="GENERATOR"Content="Microsoft Visual Studio 7.0"><metaname="CODE_LANGUAGE"Content="C#"><metaname=vs_defaultClientScript content="JavaScript"><metaname=vs_targetSchemacontent="http://schemas.microsoft.com/intellisense/ie5"><metahttp-equiv="Content-Type"content="text/html;charset=utf-8"><linkhref="Styles.css"type="text/css"rel="stylesheet"></HEAD><body><formid="WebForm1"method="post"runat="server"><h1>BetterCalendar Control Demo</h1><BrainJar:BetterCalendarid="BetterCalendar1"runat="server"><DayStyleCssClass="calendarDay"></DayStyle><DayHeaderStyleCssClass="calendarDayHeader"></DayHeaderStyle><NextPrevStyleCssClass="calendarNextPrev"></NextPrevStyle><OtherMonthDayStyleCssClass="calendarOtherMonthDay"></OtherMonthDayStyle><SelectedDayStyleCssClass="calendarSelectedDay"></SelectedDayStyle><SelectorStyleCssClass="calendarSelector"></SelectorStyle><TitleStyleCssClass="calendarTitle"></TitleStyle><TodayDayStyleCssClass="calendarTodayDay"></TodayDayStyle><WeekendDayStyleCssClass="calendarWeekendDay"></WeekendDayStyle></BrainJar:BetterCalendar></form></body></HTML>

也可以使用( 在设计模式中,右键单击工具箱,选择"自定义工具箱的常规方式向工具箱添加控件。"。选择 the".NET 框架组件"选项卡,按"浏览"按钮并选择 BrainJar.Web. UI.WebControls.dll 文件。

由于 BetterCalendar 派生自 Calendar 控件,它继承了控件。方法和事件的所有属性。 除这些之外,它还定义了四个新属性:

  • SelectAllInRange ( Boolean )

    用于星期和月选择器(。查看 Calendar.SelectionMode 属性文档)。 如果设置为 true 选定的周或者月中的所有日期。 设置为 false 仅包含单独可以选择的日期。 默认值为 false 有关如何影响控件的示例,请参见演示项目。

  • ShowLinkTitles ( Boolean )

    将这里属性设置为 true 添加 标题 属性到控件上呈现的链接,这些文本描述它的功能。 例如上个月的导航链接将被赋予一个标题,如 view 2003年12月。"

    使用标题可以提高网站表单的可以访问性。 许多浏览器呈现 标题 工具提示中的信息,但专用的浏览器可能会在语音或者盲文中呈现它。

    警告:尽管根据当前区域性生成日期和月份名称和日期,但其余的标题文本是英语。

  • MaxVisibleDate ( DateTime )

    设置用户使用下个月导航链接可以导航到的月份上限。 当当前查看的月份与 MaxVisibleDate 相同时,显示的下个月导航链接将被忽略。

  • MinVisibleDate ( DateTime )

    设置用户使用下个月导航链接可以导航到的月份的下限。 当当前查看的月份与 MinVisibleDate 相同时,显示上一个月导航链接。

注意 MixVisibleDateMaxVisibleDate 默认为 System.DateTime.MinValue,这被解释为没有设置任何限制。

设计时间支持

在 Visual Studio. NET 中,BetterCalendar 包含设计时支持的元数据,因此在设计视图中编辑控件的实例时,新属性将出现在属性窗口中。

不必使用控件,源代码包括一个名为 BrainJar.xsd的文件,可以用于删除在HTML视图中编辑控件的那些令人。

要使用模式,将 BrainJar.xsd 复制到vs_install_directoryCommon7Packagesschemasxml目录( 其中vs_install_directory是目录 Visual Studio )。 NET已经安装,通常为 C:Program FilesMicrosoft Visual Studio。 NET ),然后为它添加一个声明,在 正文 你的网站表单标记:

<bodyxmlns:BrainJar="urn:http://schemas.brainjar.com/AspNet/WebControls">

在编辑代码后为控件添加智能感知支持,可以将 BrainJar.Web. UI.WebControls.xml 文件从项目源( 在调试目录中) 复制到项目目录的bin中。

演示项目

demo项目中可以看到 BetterCalendar 控件的几个特性。 项目包含一个具有常规 Calendar 控件和 BetterCalendar 控件的单网页窗体。

两个日历都使用外部样式表(。Styles.css 文件) 中定义的CSS类进行样式化。 不同的样式用于周末,日期外,选定日期,等等 可以立即看到 Calendar 控件如何处理样式类。

在后面的代码中,BetterCalendar 控件被初始化为在当前日期之前和之后将 MinVisibleDateMaxVisibleDate 设置为 90天。

privatevoid Page_Load(object sender, System.EventArgs e)
{
 // On the initial load, set the min and max view date to 90 days// before and after today's date, respectively.if (!this.IsPostBack)
 {
 this.BetterCalendar1.MinVisibleDate = DateTime.Today.AddDays(-90);
 this.BetterCalendar1.MaxVisibleDate = DateTime.Today.AddDays(+90);
 }
}

如果浏览 BetterCalendar 控件上的月份,你将注意到,当到达相应的日期限制时,下一个或者上个月导航链接将消失。

对于两个日历,将设置 DayRender 事件处理程序。 在其中,我们将日期与相同的日期范围进行比较。 范围以外的天将它的IsSelectable 属性设置为 false

privatevoid Calendar_DayRender(object sender,
 System.Web.UI.WebControls.DayRenderEventArgs e)
{
 // Make days outside the view range nonselectable.if ((this.BetterCalendar1.MinVisibleDate!= DateTime.MinValue &&
 e.Day.Date <this.BetterCalendar1.MinVisibleDate) ||
 (this.BetterCalendar1.MaxVisibleDate!= DateTime.MinValue &&
 e.Day.Date >this.BetterCalendar1.MaxVisibleDate))
 e.Day.IsSelectable = false;
}

通过定位到日期范围的任意一端,可以看到两个日历都包含相同的不可选日期。 现在,尝试单击月选择器(">>"链接到日期标题的旁边)。 Calendar 控件每天选择每天,即使在 DayRender 事件处理程序中显式标记为非"in"。

但是,如果在 BetterCalendar 控件上选择相同的月份,则会看到标记为不可选的日期被排除。 同样适用于包含不可选日期的周。

如果你希望 BetterCalender 在周和月选择上表现得像 Calendar,那么你可以将控件属性的SelectAllInRange 设置为 true

Points of Interest

控件呈现

大多数 BetterCalendar的代码都是专用于重写的Render 方法。 Calendar 控件产生大量的HTML,并且有几个显示选项,如 NextPrevFormatNextMonthTextPrevMonthTextShowTitleTitleFormatShowDaysHeaderFirstDayOfWeek。等等 等等。 因此,为了可读性,一些工作被分解为单独的函数。

在大多数情况下,控件是使用 System.Web.UI.WebControls 现有控件构建的,而不是编写原始的HTML控件。 使用这些控件的属性和方法来分配属性和应用样式比用HTML手动写入要容易得多。

值检查( 或者不)

设置 MinVisibleDateMaxVisibleDate 或者 VisibleDate 属性时不进行值检查。 如果指定的代码中的任何一个值的值使 VisibleDate 小于 MinVisibleDate 或者 GREATER,那么添加代码就很容易。

但是,即使 VisibleDate 超出了隐含范围,它也不会在控制范围内出现问题。 因此,不是抛出异常,而是留给应用程序程序员以确保这些属性是一致的。 这让你有一些灵活性,因为你不必担心以任何特定的顺序设置这些属性。

回发事件

Calendar 控件使用回发链接来处理下一个月和上个月的导航和日期选择。 在浏览器中查看日历时,可以将鼠标悬停在日期链接上,并查看以下内容:

javascript:__doPostBack('Calendar1','1646')

对于 URI,'Calendar1'是控制标识显然'1646'引用一个日期。 对一个小的猜测和实验,结果表明这些值代表了一个给定日期和January年的天数之间的间隔。

为了在 BetterCalendar 中使用相同的格式,定义了 DateTime 常量和两个方法:

privatestaticreadonly DateTime DayCountBaseDate = new DateTime(2000, 1, 1);//// Returns the number of days between the given DateTime value and the// base date.//privateint DayCountFromDate(DateTime date)
{
 return ((TimeSpan) (date - BetterCalendar.DayCountBaseDate)).Days;
}//// Returns a DateTime value equal to the base date plus the given number// of days.//private DateTime DateFromDayCount(int dayCount)
{
 return BetterCalendar.DayCountBaseDate.AddDays(dayCount);
}

对于下个月和上个月后的回链接,参数以字母'v'开头:

javascript:__doPostBack('Calendar1','V1613')

这意味着"将可见月份更改为 June,"。

对于后退链接选择一个星期或者整个月,该参数以字母'R'开头,后面的两个数字表示所选的总天数:

javascript:__doPostBack('Calendar1','R164607')

这意味着"。选择从 4开始的连续七天,2004"。

BetterCalendar 中实现的RaisePostBackEvent 事件处理解析这个参数并执行适当的操作( 更改可见月份或者选择日期或者日期范围)。

存储不可选日期

BetterCalendar.Render 方法中, System.Web.UI.WebControls.CalendarDay 还有 System.Web.UI.WebControls.TableCell 为日历显示中的每一天创建对象。 OnDayRender 事件被引发,这两个对象被传递给分配给该控件的任何 DayRender 事件处理程序,就像 Calendar 一样。

控制从事件处理程序返回后,将检查 CalendarDay.IsSelectable 属性。 如果设置为 false 一天的日期被添加到 ArrayList

// Create a list for storing nonselectable dates.ArrayList nonselectableDates = new ArrayList();for (...)
 for (...)
. . .
 // Create a CalendarDay and a TableCell for the date. CalendarDay day = this.Day(date);
 TableCell cell = this.Cell(day);
 // Raise the OnDayRender event.this.OnDayRender(cell, day);
 // If the day was marked nonselectable, add it to the list.if (!day.IsSelectable)
 nonselectableDates.Add(day.Date.ToShortDateString());

显而易见的事情是将这个列表保存到视图状态。 但是,由于控件呈现,因为控件方法的SaveViewState 已经被调用。

而是将数据存储在添加到页面中的隐藏字段中。 定义了一些方法来处理 ArrayList 中的日期转换到可以存储在隐藏表单字段中的适当字符串值。

//// Saves a list of dates to the hidden form field.//privatevoid SaveNonselectableDates(ArrayList dates)
{
 // Build a string array by converting each date to a day count// value. string[] list = new string[dates.Count];
 for (int i = 0; i < list.Length; i++)
 list[i] =
 this.DayCountFromDate(DateTime.Parse(dates[i].ToString())).ToString();
 // Get the hidden field name.string fieldName = this.GetHiddenFieldName();
 // For the field value, create a comma-separated list from the day// count values.string fieldValue =
 HttpUtility.HtmlAttributeEncode(String.Join(",", list));
 // Add the hidden form field to the page.this.Page.RegisterHiddenField(fieldName, fieldValue);
}//// Returns a list of dates stored in the hidden form field.//private ArrayList LoadNonselectableDates()
{
 // Get the value stored in the hidden form field.string fieldName = this.GetHiddenFieldName();
 string fieldValue = this.Page.Request.Form[fieldName];
 // Extract the individual day count values. string[] list = fieldValue.Split(',');
 // Convert those values to dates and store them in an array list. ArrayList dates = new ArrayList();
 foreach (string s in list)
 dates.Add(this.DateFromDayCount(Int32.Parse(s)));return dates;
}//// Returns the name of the hidden field used to store nonselectable// dates on the form.//privatestring GetHiddenFieldName()
{
 // Create a unique field name.returnString.Format("{0}_NonselectableDates", this.ClientID);
}

RaisePostBackEvent 中,当选择一个日期范围时,我们可以加载这个列表,并使用它来删除那些日期。

...this.SelectedDates.Clear();this.SelectedDates.SelectRange(date, date.AddDays(n - 1));// If SelectAllInRange is false, remove any dates found// in the nonselectable date list.if (!this.SelectAllInRange)
{
 ArrayList nonselectableDates = this.LoadNonselectableDates();
 foreach(DateTime badDate in nonselectableDates)
 this.SelectedDates.Remove(badDate);
}

历史记录

  • ,19,2004
    • 初始版本。
  • 14,2004
    • 更新以改进全球化支持。 月份和日名称。缩写。日期格式和星期的默认第一天都基于当前区域性。
  • 24,2004
    • 修复 Bug 事件,在选择一个星期或者月时不总是引发 SelectionChanged 事件。

WEB  webcontrol  
相关文章