扩展CalendarExtender的应用场合
ASP.NET AJAX Control Toolkit中的CalendarExtender在用于选择日期的时候已经非常方便,网上也有很多Tips来解决语言是英语、显示不正常等问题。但该控件默认只和一个文本框配合使用(通过TargetControlID属性),也就是会将完整的日期填到一个文本框中。如果碰到了需要将年份、月份和日期分别显示到三个文本框的场合,该怎么办呢?本文来解决这个问题!
新建网站后创建一个名为AdvancedCalendarExtender.ascx的用户控件,封装三个TextBox、一个ImageButton和CalendarExtender,其中ImageButton用于弹出日历:
AdvancedCalendarExtender.ascx
2<asp:TextBox ID="txtYear" runat="server" Width="35px" MaxLength="4"></asp:TextBox> /
3<asp:TextBox ID="txtMonth" runat="server" Width="20px" MaxLength="2"></asp:TextBox> /
4<asp:TextBox ID="txtDay" runat="server" Width="20px" MaxLength="2"></asp:TextBox>
5<asp:ImageButton ID="btnSelector" runat="server" ImageUrl="~/images/icon_calendar.gif" />
6<ajax:CalendarExtender ID="calExt" runat="server" Format="yyyy/MM/dd" PopupButtonID="btnSelector" TargetControlID="txtYear"></ajax:CalendarExtender>
注意CalendarExtender的Format设置成了yyyy/MM/dd,格式在此处不是特别重要,但为了后面的便利,最好设置成带“/”或“-”这类分隔符的格式。另外TargetControlID设置成了txtYear,作为默认的方式,控件运行的时候会将完整的日期填进第一个仅仅只用于显示年份的文本框。
CalendarExtender只有几个基本的服务器端事件,并未提供更为合适的事件来帮助我们解决问题。但我们可以使用服务器端的属性映射到客户端,再用客户端的JavaScript来操作文本框。查看属性列表,刚好有个OnClientDateSelectionChanged属性可供我们使用,现在,设置OnClientDateSelectionChanged属性,用JavaScript编写select()函数:
AdvancedCalendarExtender.ascx
2<script language="javascript" type="text/javascript">
3 function select() {
4 var date = $get("<%= this.ClientID %>_txtYear").value;
5 date = date.split("/");
6 $get("<%= this.ClientID %>_txtYear").value = date[0];
7 $get("<%= this.ClientID %>_txtMonth").value = date[1];
8 $get("<%= this.ClientID %>_txtDay").value = date[2];
9 }
10</script>
11<asp:TextBox ID="txtYear" runat="server" Width="35px" MaxLength="4"></asp:TextBox> /
12<asp:TextBox ID="txtMonth" runat="server" Width="20px" MaxLength="2"></asp:TextBox> /
13<asp:TextBox ID="txtDay" runat="server" Width="20px" MaxLength="2"></asp:TextBox>
14<asp:ImageButton ID="btnSelector" runat="server" ImageUrl="~/images/icon_calendar.gif" />
15<ajax:CalendarExtender ID="calExt" runat="server" Format="yyyy/MM/dd" PopupButtonID="btnSelector" TargetControlID="txtYear" OnClientDateSelectionChanged="select"></ajax:CalendarExtender>
JavaScript的select()函数通过$get()方法来获取文本框中的日期。这里要注意的是,文本框因为用在用户控件里,它在客户端浏览器里所对应<input>的ID不再是服务器上的txtYear,而是“用户控件ID_文本框ID”的格式。因此我们通过<%= %>来输出用户控件将来在客户端的ID。只要了解这点,剩下的select()函数的逻辑就很简单了:获取第一个文本框中完整的日期,使用split()方法按“/”切割(这就是之前为什么用yyyy/MM/dd格式),切割后得到数组,把数组里的内容分别填到三个文本框里。完成后,将AdvancedCalendarExtender.ascx添加到页面中,运行后效果如下图所示:
AdvancedCalendarExtender已经可以正常工作了!但别忙着高兴,试试在同一个页面中,将该用户控件使用两次,得到了什么效果?
当你从第一个日历中选中日期后,会看到如上图所示的效果。原因就是两个用户控件会把同名的select()函数生成两遍!我们让这两个select()不同名就可以了。下面将用户控件改成:
AdvancedCalendarExtender.ascx
2<script language="javascript" type="text/javascript">
3 function select<%= this.ClientID %>() {
4 var date = $get("<%= this.ClientID %>_txtYear").value;
5 date = date.split("/");
6 $get("<%= this.ClientID %>_txtYear").value = date[0];
7 $get("<%= this.ClientID %>_txtMonth").value = date[1];
8 $get("<%= this.ClientID %>_txtDay").value = date[2];
9 }
10</script>
11<asp:TextBox ID="txtYear" runat="server" Width="35px" MaxLength="4"></asp:TextBox> /
12<asp:TextBox ID="txtMonth" runat="server" Width="20px" MaxLength="2"></asp:TextBox> /
13<asp:TextBox ID="txtDay" runat="server" Width="20px" MaxLength="2"></asp:TextBox>
14<asp:ImageButton ID="btnSelector" runat="server" ImageUrl="~/images/icon_calendar.gif" />
15<ajax:CalendarExtender ID="calExt" runat="server" Format="yyyy/MM/dd" PopupButtonID="btnSelector" TargetControlID="txtYear"></ajax:CalendarExtender>
注意:1、JavaScript函数名的写法;2、因为将来JavaScript函数名不固定,所以我们无法直接在声明语句中静态设置OnClientDateSelectionChanged属性。我们打开AdvancedCalendarExtender.ascx.cs,在Page_Load()方法里面动态的设置OnClientDateSelectionChanged属性:
AdvancedCalendarExtender.ascx.cs
2{
3 calExt.OnClientDateSelectionChanged = "select" + ClientID;
4}
这样在同一个页面中多次使用AdvancedCalendarExtender就没问题了!还可以为AdvancedCalendarExtender封装年份、月份和日期属性,方便日后在页面中使用。
最终运行效果如下图所示:
最后给出AdvancedCalendarExtender.ascx和测试页面的完整代码:
AdvancedCalendarExtender.ascx
2<script language="javascript" type="text/javascript">
3 function select<%= this.ClientID %>() {
4 var date = $get("<%= this.ClientID %>_txtYear").value;
5 date = date.split("/");
6 $get("<%= this.ClientID %>_txtYear").value = date[0];
7 $get("<%= this.ClientID %>_txtMonth").value = date[1];
8 $get("<%= this.ClientID %>_txtDay").value = date[2];
9 }
10</script>
11<asp:TextBox ID="txtYear" runat="server" Width="35px" MaxLength="4"></asp:TextBox> /
12<asp:TextBox ID="txtMonth" runat="server" Width="20px" MaxLength="2"></asp:TextBox> /
13<asp:TextBox ID="txtDay" runat="server" Width="20px" MaxLength="2"></asp:TextBox>
14<asp:ImageButton ID="btnSelector" runat="server" ImageUrl="~/images/icon_calendar.gif" />
15<ajax:CalendarExtender ID="calExt" runat="server" Format="yyyy/MM/dd" PopupButtonID="btnSelector" TargetControlID="txtYear"></ajax:CalendarExtender>
AdvancedCalendarExtender.ascx.cs
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.UI;
6using System.Web.UI.WebControls;
7
8public partial class AdvancedCalendarExtender : System.Web.UI.UserControl
9{
10 protected void Page_Load(object sender, EventArgs e)
11 {
12 calExt.OnClientDateSelectionChanged = "select" + ClientID;
13 }
14
15 public string Year
16 {
17 get { return txtYear.Text; }
18 set { txtYear.Text = value; }
19 }
20 public string Month
21 {
22 get { return txtMonth.Text; }
23 set { txtMonth.Text = value; }
24 }
25
26 public string Day
27 {
28 get { return txtDay.Text; }
29 set { txtDay.Text = value; }
30 }
31}
Default.aspx
2<%@ Register src="AdvancedCalendarExtender.ascx" tagname="AdvancedCalendarExtender" tagprefix="mine" %>
3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4<html xmlns="http://www.w3.org/1999/xhtml">
5<head runat="server">
6 <title>Advanced CalendarExtender</title>
7</head>
8<body>
9 <form id="form1" runat="server">
10 <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
11 <asp:UpdatePanel ID="UpdatePanel1" runat="server">
12 <ContentTemplate>
13 <p>From: <mine:AdvancedCalendarExtender ID="aceFromDate" runat="server" /></p>
14 <p>To: <mine:AdvancedCalendarExtender ID="aceToDate" runat="server" /></p>
15 <p><asp:Button ID="btnSubmit" runat="server" Text="Submit" onclick="btnSubmit_Click" /></p>
16 <p><asp:Label ID="lblResult" runat="server"></asp:Label></p>
17 </ContentTemplate>
18 </asp:UpdatePanel>
19 </form>
20</body>
21</html>
Default.aspx.cs
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.UI;
6using System.Web.UI.WebControls;
7
8public partial class _Default : System.Web.UI.Page
9{
10 protected void btnSubmit_Click(object sender, EventArgs e)
11 {
12 lblResult.Text = string.Format("Your selection is from {0}-{1}-{2} to {3}-{4}-{5}.", aceFromDate.Year, aceFromDate.Month, aceFromDate.Day, aceToDate.Year, aceToDate.Month, aceToDate.Day);
13 }
14}
Enjoy!