ASP服务器端JavaScript如日历弹出式菜单

分享于 

20分钟阅读

Web开发

  繁體

介绍

在一个项目中,我发现了一种完整的方法,使它的成为一个名为a的ASP.NET 服务器端日历控件 ! 这对于任何项目来说都很容易。 在其他控件上,我可以使用日历显示功能,在不同的月份移动,在本质上,我使得 ASP.NET 服务器的侧控制工作就像在网络上的那些精美的JavaScript日历对象一样。 它还保持了对选择跌落和其他类似控件( 有一个警告,当你更改月份时,它不会做这个,很多我的chagrin )的控制。

设置

要在 ASP.NET 2.0 ( 或者你甚至可以在 1.1年使用它) web应用程序项目中工作,首先需要将 Calendar.ascx ( 当然,Calendar.ascx.cs ) 导入到你的项目中,在你保存用户控件的一般地方。 我把我的放在一个我名为的文件夹里。

接下来,无论你使用什么级别的应用程序,都可以看到图像,我通常将项目名称作为一个插件 web.config 应用程序设置变量。 当你的应用程序不是 root web应用程序时,这很有用。 如果是 root,则只需将它的从日历用户控件中去除:

<configuration><appSettings><addkey="ApplicationName"value="ASP2.0_Calendar"/></appSettings><connectionStrings/>...the Calendar.ascx code:<imgborder="0"src="/<%= ConfigurationManager.AppSettings["ApplicationName"] %>/images/x.gif"align="top"></a>

现在,你可以使用我的样式表和日历主题,或者为日历制作自己的日历。 使用 mine,只需将 Calendar.skin 文件放入应用程序 app_themes/calendartheme文件夹。

below 是解决方案资源管理器路径在实际项目中的外观。

你还需要将主题引用添加到页面标题中:

<%@PageLanguage="C#".....Theme="CalendarTheme"Title="ASP2.0 Pop-Up Calendar Example"StylesheetTheme="CalendarTheme"%>

现在你已经准备好将日历控件添加到页面。

使用代码

在 ASP.NET 中添加用户控件的第一件事是使用页面将控件 register。 这基本上允许页面查看和允许控件的类型。 在设计器模式下,Visual Studio. NET 通常会为你执行这里操作,并在页面上直接从解决方案资源管理器中删除控件:

控件对象也可以使用以下方法手动添加 @Register 标记,如下面所示:

<%@RegisterSrc="UserControls/Calendar.ascx"TagName="Calendar"TagPrefix="uc1"%>

接下来,你要添加实际控件:

<uc1:CalendarID="EndDateCalendar"runat="server"/>

我使行标记 <td> 有一个 onclick 事件,因这里如果单击文本框或者小日历 icon,则日历将弹出。 然后,你可以在日历弹出的X 方框图像中关闭它 !

<tdvalign="top"align=left nowraponclick="javascript:setDisplay('<%=EndDateCalendar.ClientName %>', 
 false);setDisplay('<%=StartDateCalendar.ClientName %>',true);">....Text Box and Image</td>

注意,每个日历对象都有一个方法来获取它的客户端 NAME。 我这样做的话,我们可以从控件中将JavaScript与JavaScript合并,并调用相应的JavaScript显示方法。

现在,让我们来看看日历工作的一些要点。

首先,让我们看看页面本身所需要的附加内容。 我说页面,但这可以能是任何控制,甚至是另一个用户控件。 我添加了一个方法,允许将文本框对象注册到日历控件。 这样可以在文本框或者隐藏字段和日历之间自动交换数据。 现在,只有数据绑定文本框和更改对象值的日历日期才会在页面上添加事件。 我尝试添加一些代码来捕获 TextBox.OnTextChanged 事件,但这并没有奏效。 我怀疑这是因为事件是在日历控件上而不是在页面上。 虽然这很奇怪,因为日历上的TextBox.OnDataBinding 事件确实被调用。 任何人都知道这是为什么?

protectedvoid Page_Init(object sender, EventArgs e)
{
 if (Page.IsPostBack) return;
 this.StartDateCalendar.RegisterControl(ref StartDate);
 this.EndDateCalendar.RegisterControl(ref EndDate);
 this.Page.LoadComplete += new EventHandler(Page_LoadComplete);
}

我们需要添加一些代码来为页面的Page.LoadComplete 事件添加事件处理程序,或者将日历显示在。 我是这样做的,因为我希望日历控件在页面上完成它的他任何事后都要加载它的数据。 无论你是否可以使它在正常的页面负载中工作,我将放弃你。

我将每个日历控件的文本框作为它的文本选择控件值的日历。 我这样做,以便在更改日历选择后重新加载页面,我们得到了在文本框中显示的值。 因此,从日历控件中选择值并刷新页时,所选值是文本框中的值。 之后,我检查页面上的回发,如果不是( 这是页面的初始加载),那么我将设置文本框和日历控件值。 在这里,你将使用来自数据源的值填充页面。

另一种方法是对文本框控件进行处理,该控件将调用calendar控件上的TextBox_DataBinding 事件处理程序。 这就释放了日历对象上的值,特别是。

protectedvoid Page_LoadComplete(object sender, EventArgs e)
{
 StartDate.Text = StartDateCalendar.SelectedDate;
 EndDate.Text = EndDateCalendar.SelectedDate;
 if (Page.IsPostBack) return;
 this.StartDate.Text = DateTime.Now.ToShortDateString();
 this.StartDateCalendar.SelectedDate = this.StartDate.Text;
 this.EndDate.Text = DateTime.Now.AddDays(12).ToShortDateString();
 this.EndDateCalendar.SelectedDate = this.EndDate.Text;
}//.....Alternate waythis.StartDate.Text = DateTime.Now.ToShortDateString();this.StartDate.DataBind();this.EndDate.Text = DateTime.Now.AddDays(12).ToShortDateString();this.EndDate.DataBind();

接下来,我们需要为 TextChanged 事件添加事件处理程序,在控件文本文本文本更改时设置两个事件。 这将确保日历控件始终具有与它们的文本框相同的值。 如前所述,无法获得注册文本框控件的事件。 我怀疑它与日历上的位置有关但我现在不知道。 总之,我在这里的页面上的文本框控件是,并且它工作正常。

<--theStartDatetextboxonDefault.aspx--><asp:TextBoxID="StartDate"runat="server"MaxLength="10"OnTextChanged="StartDate_TextChanged"ValidationGroup="EditGroup"Width="100px"></asp:TextBox>.......the EndDate textbox on Default.aspx<asp:TextBoxID="EndDate"runat="server"MaxLength="10"OnTextChanged="EndDate_TextChanged"ValidationGroup="EditGroup"Width="100px"></asp:TextBox>

Default.cs file:

#region Calendarprotectedvoid StartDate_TextChanged(object sender, EventArgs e)
{
 StartDateCalendar.SelectedDate = StartDate.Text;
}protectedvoid EndDate_TextChanged(object sender, EventArgs e)
{
 EndDateCalendar.SelectedDate = EndDate.Text;
}#endregion

现在我们可以查看用户控件。

注意到了 Page.Load 事件处理程序,它检查名为 IsMonthChanging的属性,以设置隐藏字段。 这将设置控件的对象和状态的日历值。 它还会更改 IsMonthChanging 值的注册值,如果 false :

protectedvoid Page_Load(object sender, EventArgs e)
{ 
 if (!IsMonthChanging)
 { 
 this.SelectedDate = DateCalendar.SelectedDate.ToShortDateString();
 if (Page.FindControl(RegisteredControlName.Value) is TextBox)
 {
 ((TextBox)FindRegisteredControl()).Text = this.SelectedDate;
 }
 elseif (FindRegisteredControl() is HiddenField)
 {
 ((HiddenField)FindRegisteredControl()).Value = this.SelectedDate;
 }
 }
}

在下面我们看到了两个方法:一个文本框或者一个带有日历的隐藏域。 这是因为我们可以数据绑定,并且有日历和文本框控件自动交换它们的值:

publicvoid RegisterControl(ref TextBox controlToRegister)
{
 //controlToRegister.TextChanged += new EventHandler(TextBox_TextChanged); controlToRegister.DataBinding += new EventHandler(TextBox_DataBinding);
 controlToRegister.AutoPostBack = true;
 RegisteredControlName.Value = controlToRegister.ID;
}publicvoid RegisterControl(ref HiddenField controlToRegister)
{
 controlToRegister.DataBinding += new EventHandler(HiddenField_DataBinding); 
 RegisteredControlName.Value = controlToRegister.ID;
}

我们看到的是 IsMonthChanging 属性,它告诉我们我们没有更改日历值,而是更改显示的月份。 这不会影响控件的实际值:

protectedbool IsMonthChanging
{
 get { return Convert.ToBoolean(MonthChanging.Value); }
}

ClientName 属性为控件外部的客户端JavaScript提供了控件呈现 NAME的客户端引用。 这是我们为整个控件使用的特殊 NAME,基于控件属性的ClientId:

publicstring ClientName
{
 get { returnthis.ClientID + "_Selectable"; }
}

SelectedDate 属性允许我们获取或者设置控件实际日期的值。 它使用一个隐藏文本字段来维护控件的状态并检查错误。 如果发生输入错误,则将该控件设置为最后一个有效的日期值:

publicstring SelectedDate
{
 get {
 if (DateValue.Value!= "1/1/0001")
 return DateValue.Value;
 elsereturnnull;
 }
 set {
 try {
 DateCalendar.SelectedDate = Convert.ToDateTime(value);
 DateCalendar.VisibleDate = Convert.ToDateTime(value);
 DateValue.Value = value;
 }
 catch (Exception)
 {
 DateCalendar.SelectedDate = Convert.ToDateTime(DateValue.Value);
 DateCalendar.VisibleDate = Convert.ToDateTime(DateValue.Value);
 }
 }
}

接下来是两个事件处理程序: DateCalendar_SelectionChanged,用于更改控件的状态和值,以及 DateCalendar_VisibleMonthChanged,它允许我们确定显示的控件的服务器当前月份。

protectedvoid DateCalendar_SelectionChanged(object sender, EventArgs e)
{
 DateValue.Value = DateCalendar.SelectedDate.ToShortDateString();
 if (Page.FindControl(RegisteredControlName.Value) is TextBox)
 {
 ((TextBox)FindRegisteredControl()).Text = this.SelectedDate;
 }
 elseif (FindRegisteredControl() is HiddenField)
 {
 ((HiddenField)FindRegisteredControl()).Value = this.SelectedDate;
 }
 if (Page.IsPostBack)
 {
 MonthChanging.Value = "False";
 }
}protectedvoid DateCalendar_VisibleMonthChanged(object sender, MonthChangedEventArgs e)
{
 MonthChanging.Value = "True";
}

最后是两个事件处理程序: TextBox_DataBinding,用于在注册文本框与数据绑定时更改控件值,HiddenField_DataBinding 是隐藏字段的替代方法,并且

/*protected void TextBox_TextChanged(object sender, EventArgs e)
{
 this.SelectedDate = ((TextBox)FindRegisteredControl()).Text;
}*/protectedvoid TextBox_DataBinding(object sender, EventArgs e)
{
 this.SelectedDate = ((TextBox)FindRegisteredControl()).Text;
} protectedvoid HiddenField_DataBinding(object sender, EventArgs e)
{
 this.SelectedDate = ((HiddenField)FindRegisteredControl()).Value;
}

我们有一些需要注意的东西,在ASCX文件中。 我们显示或者隐藏控件的方式是由它隐藏字段 IsMonthChanging的布尔设置决定的。 通过在标记中设置客户端标识,然后在标记的样式中,通过检查 IsMonthChanging 属性来确定控件是否显示。 还要注意,divstyleposition 属性设置为 absolute。 这样做可以使日历在页面的其余部分浮动。 我们还有一个 IFrame,允许我们将控件放下来,从而显示在日历的顶部:

<iframeid="<%= this.ClientName %>_overShelf"scrolling="no"frameborder="0"style="position:absolute; top:0px; left:0px; display:none;"></iframe><divid="<%= this.ClientName %>"style="z-index:99999; position:absolute; display:none">

显示函数具有单独的控件 NAME,因此我们可以从控件外部调用控件上的确切客户端JavaScript方法 NAME。 我们在客户端方法中设置 IFramediv 如何显示在页面上:

function <%= this.ClientName %>_SetDisplay(doDisplay)
{
 if(doDisplay == true)
 {
 document.getElementById('<%= this.ClientName %>').style.display='inline'; 
 document.getElementById('<%= this.ClientName %>_overShelf').style.zIndex = 
 document.getElementById('<%= this.ClientName %>').style.zIndex - 1;
 document.getElementById('<%= this.ClientName %>_overShelf').style.width = 
 document.getElementById('<%= this.ClientName %>').offsetWidth;
 document.getElementById('<%= this.ClientName %>_overShelf').style.height = 
 document.getElementById('<%= this.ClientName %>').offsetHeight;
 document.getElementById('<%= this.ClientName %>_overShelf').style.top = 
 document.getElementById('<%= this.ClientName %>').offsetTop;
 document.getElementById('<%= this.ClientName %>_overShelf').style.left = 
 document.getElementById('<%= this.ClientName %>').offsetLeft;
 document.getElementById('<%= this.ClientName %>_overShelf').style.x = 
 document.getElementById('<%= this.ClientName %>').offsetTop;
 document.getElementById('<%= this.ClientName %>_overShelf').style.left = 
 document.getElementById('<%= this.ClientName %>').offsetLeft;
 document.getElementById('<%= this.ClientName %>_overShelf').style.display = 'block';
 document.getElementById('<%= MonthChanging.ClientID %>').value="True";
 }
 else {
 document.getElementById('<%= this.ClientName %>').style.display='none'; 
 document.getElementById('<%= this.ClientName %>_overShelf').style.zIndex = 
 document.getElementById('<%= this.ClientName %>').style.zIndex - 1;
 document.getElementById('<%= this.ClientName %>_overShelf').style.width = 
 document.getElementById('<%= this.ClientName %>').offsetWidth;
 document.getElementById('<%= this.ClientName %>_overShelf').style.height = 
 document.getElementById('<%= this.ClientName %>').offsetHeight;
 document.getElementById('<%= this.ClientName %>_overShelf').style.top = 
 document.getElementById('<%= this.ClientName %>').offsetTop;
 document.getElementById('<%= this.ClientName %>_overShelf').style.left = 
 document.getElementById('<%= this.ClientName %>').offsetLeft;
 document.getElementById('<%= this.ClientName %>_overShelf').style.x = 
 document.getElementById('<%= this.ClientName %>').offsetTop;
 document.getElementById('<%= this.ClientName %>_overShelf').style.left = 
 document.getElementById('<%= this.ClientName %>').offsetLeft;
 document.getElementById('<%= this.ClientName %>_overShelf').style.display = 'none';
 document.getElementById('<%= MonthChanging.ClientID %>').value="False";
 }

运行代码

现在,运行代码并检查控件在运行时的工作方式。 我们在屏幕上看到我们的文本框值显示了 inside 各自的文本框:

接下来,如果我们单击日历 icon 或者文本框,就会看到显示的日历只是 below 文本框。 由于控件中标记属性 <div>styleposition 设置为 absolute,该控件似乎在其他控件上浮动。 此外,请注意,文本框中的日期在日历中被选中为红色:

现在,如果希望将日历更改为其他月份,可以单击日历上的<或者> 链接。 这会导致邮件回到任何它的他 ASP.NET 服务器端日历控件,但当页面备份时,日历将不会消失。 直到你单击日历顶部的值或者X icon,它才会继续 ! 超酷 !

现在如果更改日历的值,日历将消失,并且文本框得到新值。 如果再次单击文本框或者日历 icon,则会看到正确月份中弹出的日历,选择正确的数据。

Points of Interest

我在 IE 中测试过。 我认为 跨浏览器,用来显示控件的客户端脚本不能正常工作。 很可能对这段代码的良好重构将包括一些 跨浏览器 端代码。 如果你发送这个代码以可以接受的方式进行改进,我将修改文章并给你你的信用。

此外,还可以改进文本框和日历对象如何存在于( 如 上面 所述) 中。 你想要共享的任何更好的更改也将被添加,并且提交者将刚刚在文章中收到他或者她。

感谢你阅读 !

更新

  • 01/25/06 - 我已经添加了一些支持在母版页关系中查找控件。

JAVA  Javascript  Server  CAL  SID  LIKE