WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

CalendarExtender の利用例

by WebSurfer 7. May 2022 14:04

Ajax Control Toolkit の CalendarExtender を、下の画像のようにテキストボックスなし(実際は非表示)で、img 要素(普通のボタンでも可)をクリックして表示し、ユーザーがカレンダー上で選択した日付をサーバー側に送信する方法を書きます。

CalendarExtender

今時 CalendarExtender を使うことはあまりなさそうで、しかもこの記事に書いてあるような特殊な使い方をすることはまずなさそうですが、せっかく考えたので備忘録として書いておくことにしました。

CalendarExtender の基本的な使い方については、DevExpress のデモページ「Calendar Demonstration」と、@IT の記事「Calendarコントロールで日付入力ボックスを定義するには?」が参考になると思いますので一読されることをお勧めします。

カレンダーを img 要素(または普通のボタン)をクリックして表示する方法ですが、DevExpress のデモページの「Calendar with an associated button」と @IT の記事の「補助カレンダーを任意のボタンから起動する」を見てください。

この記事では、DevExpress のデモページと同じ画像を img 要素を使って表示し、CalendarExtender の PopupButtonID プロパティに img 要素の id を設定して、その img 要素をクリックしてカレンダーを表示します。img 要素に代えて <button type="button"> も使えます。ただし、クリックするとポストバックが起こる Button コントロールなどを使う場合は、ポストバックが起こらないように処置する必要があるので注意してください。

CalendarExtender の対象となるテキストボックスを指定する TargetControlID の設定は必須です。なので必ずテキストボックスをページに配置する必要があります。非表示にしたい場合は CSS で display: none; を設定してください。TextBox.Visible プロパティを false に設定するのはダメです。

カレンダーの表示位置はデフォルトでは自動的にテキストボックス直下になります。テキストボックスを非表示にする場合は自力で JavaScript を書いてカレンダーの表示位置を設定する必要があります。

その方法は Code Project の記事 Ajax CalendarExtender pop up position の Solution 1 を参考にさせてもらいました。

最後に、ユーザーが選択した日付をサーバーに送信する方法ですが、選択した時点で日付はテキストボックスに自動的に入力されますので、何らかの手段でポストバックをかければサーバー側で Text プロパティから取得できます。

CalendarExtender の OnClientDateSelectionChanged プロパティに JavaScript のリスナを設定してそこで取得し、Ajax を使ってサーバーに送信することもできます。

以上を実装したサンプルコードを下に載せておきます。この記事の上の画像を表示したものです。

CalendarExtender.aspx.cs

using System.Web.UI;

namespace WebForms1
{
    public partial class CalendarExtender : System.Web.UI.Page
    {
        protected void Page_Init(object sender, EventArgs e)
        {
            // マスターページに配置した ScriptManager のプロパティ
            // EnableScriptGlobalization を true に設定する
            ScriptManager sm = ScriptManager.GetCurrent(this.Page);
            sm.EnableScriptGlobalization = true;
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            // ユーザーが選択した日付を取得・表示
            Label1.Text = TextBox1.Text;
        }
    }
}

CalendarExtender.aspx.cs

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master"    
    AutoEventWireup="true" CodeBehind="CalendarExtender.aspx.cs" 
    Inherits="WebForms1.CalendarExtender" %>

<asp:Content ID="Content1" ContentPlaceHolderID="HeaderContent" runat="server">

    <script type="text/javascript">
        // Calendar の表示位置を img 要素直下に調整する
        function onCalendarShown(sender, args) {
            var img = $get('image1');

            sender._popupDiv.parentElement.style.top =
                img.offsetTop + img.height + 'px';
            sender._popupDiv.parentElement.style.left =
                img.offsetLeft + 'px';
        }

        // ユーザーが日付を選択すると発生するイベントのリスナ
        function sendResult(sender) {
            // 選択した日付は以下のようにして取得できる
            var selectedDate = sender.get_selectedDate();

            // ポストバックすればサーバー側では TextBox1.Text 
            // プロパティから選択した日付を取得できる
            var btn = $get('<%=Button1.ClientID %>');
            btn.click();
        }
    </script>

    <style type="text/css">
        /* TextBox1 を非表示にする */
        .style1 {
            display: none;
        }
    </style>

</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <h3>Ajax Control Toolkit CalendarExtender</h3>    
   
    <asp:TextBox ID="TextBox1" runat="server" CssClass="style1">
    </asp:TextBox>

    <%--PopupButtonID に設定するのはサーバーコントロールでなくても可--%>
    <img src="images/Calendar_scheduleHS.png" id="image1" alt="" />

    <ajaxToolkit:CalendarExtender ID="CalendarExtender1" 
        runat="server" 
        PopupButtonID="image1"
        TargetControlID="TextBox1" 
        DaysModeTitleFormat="yyyy年M月"
        TodaysDateFormat="yyyy年M月d日"
        Format="yyyy/MM/dd"
        OnClientDateSelectionChanged="sendResult" 
        OnClientShown="onCalendarShown" />

    <br />
    <%--ポストバックするための Button コントロール--%>
    <asp:Button ID="Button1" runat="server" Text="PostBack" />

    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</asp:Content>

なお、本題とは関係ないことですが、カレンダー上の日付の表示はデフォルトではなく、先の記事「CalendarExtender の日付の表示」に書いたように日本語形式にしています。

Tags: ,

AJAX

CheckBox 付き Calendar(その2)

by WebSurfer 12. December 2013 21:24

先の記事 CheckBox 付き Calendar コントロール で「チェックを入れる/外すたびにいちいちポストバックしないでもすむ方法を考え付いたら、別途記事を書きます」と書きましたが、今頃になってそれを作ってみました。

CheckBox 付き Calendar

前のサンプルでは、CheckBox の onclick 属性にポストバックするスクリプトを設定して、CheckBox がクリックされるたびポストバックしてサーバ側でチェック結果を取得して ViewState に保存していました。

それをやめて、別の月に移動する時またはボタンクリックしてポストバックされる時にまとめてクライアント側でチェック結果を取得し、それをサーバーに送信して ViewState に保存するようにしました。

以下にそのコードを示します。詳しくはコメントに書きましたので、それを見てください。

また、実際に動かして試すことができるよう 実験室 にアップしました。興味のある方は試してみてください。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  // CheckBox をクリックするたびポストバックしないで、ページン
  // グでポストバックした際に、まとめてチェック結果を取得し、
  // リスト checkedDates を更新する。

  // チェックされている日付のリスト。ViewState に保持する。
  protected List<DateTime> checkedDates;

  protected void Page_Load(object sender, EventArgs e)
  {
    // ViewState から日付リスト checkedDates を取得。
    object obj = ViewState["CheckedDates"];
    if (obj != null)
    {
      checkedDates = (List<DateTime>)obj;
    }
    else
    {
      // ViewState が未設定の場合は新たに初期化。
      checkedDates = new List<DateTime>();
    }
        
    // ポストバックの時は、隠しフィールドでポストされたデータ
    // で日付リスト checkedDates を更新する。
    if (Page.IsPostBack)
    {
      char[] chars = new char[] { ',' };
      string s = 
          Request.Form["__CHECKEDIDLIST"].Trim(chars);
      string[] check = s.Split(chars);
      s = Request.Form["__UNCHECKEDIDLIST"].Trim(chars);
      string[] uncheck = s.Split(chars);

      foreach (string id in check)
      {
        if (!String.IsNullOrEmpty(id))
        {
          checkedDates.Remove(DateTime.Parse(id));
        }
      }

      foreach (string id in uncheck)
      {
        if (!String.IsNullOrEmpty(id))
        {
          checkedDates.Remove(DateTime.Parse(id));
        }
      }

      foreach (string id in check)
      {
        if (!String.IsNullOrEmpty(id))
        {
          checkedDates.Add(DateTime.Parse(id));
        }
      }

      ViewState["CheckedDates"] = checkedDates;
    }

    // form を送信する際、CheckBox のチェック有無を調べて、
    // その結果をサーバーに送信するスクリプトを設定。
    String csname = "OnSubmitScript";
    Type cstype = this.GetType();
    ClientScriptManager cs = Page.ClientScript;
    if (!cs.IsOnSubmitStatementRegistered(cstype, csname))
    {
      String cstext =
        "getCheckedDates('" + Calendar1.ClientID + "');";
      cs.RegisterOnSubmitStatement(cstype, csname, cstext);
    }
  }    

  protected void Calendar1_DayRender(object sender, 
      DayRenderEventArgs e)
  {
    CheckBox cb = new CheckBox();

    // このセルの日付を CheckBox の ID に設定。
    cb.ID = e.Day.Date.ToShortDateString();

    // このセルの日付がリスト checkedDates にあれば CheckBox
    // にチェックを入れる。
    foreach (DateTime day in checkedDates)
    {
      if (e.Day.Date == day)
      {
        cb.Checked = true;
        e.Cell.Controls.Add(cb);
        return;
      }            
    }
        
    cb.Checked = false;
    e.Cell.Controls.Add(cb);
  }

  // ボタンクリックで最終結果を取得。
  protected void Button1_Click(object sender, EventArgs e)
  {
    string str = "Selected Dates:";
    foreach (DateTime day in checkedDates)
    {
      str += "<br />" + day.ToShortDateString();
    }
    Label1.Text = str;
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>Calendar with CheckBox</title>
  <script src="Scripts/jquery-1.6.2.min.js" type="text/javascript">
  </script>
  <script type="text/javascript">
  //<![CDATA[
    // CheckBox のチェック有無を調べて、その結果を隠し
    // フィールドに設定するスクリプト。
    function getCheckedDates(calendarClientId) {
      var checked = "";
      var unchecked = "";

      $('#' + calendarClientId + ' input:checkbox').each(
        function () {
          // MasterPage を使うなど、名前付コンテナに Calendar
          // を入れると id が違ってくるので注意。
          var id = $(this).attr('id');                    
          if ($(this).attr('checked') == "checked") {
            checked += ',' + id;
          } else {
            unchecked += ',' + id;
          }
        });

      $('#__CHECKEDIDLIST').val(checked);
      $('#__UNCHECKEDIDLIST').val(unchecked);
    }
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">

  <%--チェック結果をサーバに送信する隠しフィールド。--%>
  <input type="hidden" 
    name="__CHECKEDIDLIST" 
    id="__CHECKEDIDLIST" 
    value="" />
  <input type="hidden" 
    name="__UNCHECKEDIDLIST" 
    id="__UNCHECKEDIDLIST" 
    value="" />

  <div>
    <asp:Calendar ID="Calendar1" 
      runat="server" 
      ondayrender="Calendar1_DayRender" 
      SelectionMode="None" >
    </asp:Calendar>
    <asp:Button ID="Button1" 
      runat="server" 
      Text="Show selected dates" 
      onclick="Button1_Click" />
    <br />
    <asp:Label ID="Label1" runat="server" />        
  </div>
  </form>
</body>
</html>

Tags:

ASP.NET

CalendarExtender の日付の表示

by WebSurfer 26. July 2013 11:48

Ajax Control Toolkit の CalendarExtender で日本語形式の日付を表示するにはどうすればよいかという話です。

まず、ToolkitScriptManager と CalendarExtender の設定がデフォルト状態(Visual Studio でドラッグ&ドロップしただけの状態)の場合は下の画像のような表示になります。

デフォルトでのカレンダーの表示

カルチャは ja-JP と認識されていますが、(1) TextBox に入力される日付の形式が M/d/yyyy(米国式)、(2) カレンダーの曜日が英語、(3) カレンダーのタイトルと今日の日付の表示が米国式になってしまいます。

特に問題になるのが「(1) TextBox に入力される日付の形式が M/d/yyyy」です。M/d/yyyy 形式では、CompareValidator による検証や、サーバー側での DateTime 型への変換の際などにパースがうまくいかず、期待した結果にならないということがあります。

カルチャが ja-JP の時に TextBox に入力される日付が yyyy/MM/dd 形式となるようにするには、ToolkitScriptManager の EnableScriptGlobalization プロパティを true に設定してやります。その結果が下の画像です。

EnableScriptGlobalization を true に設定

MSDN ライブラリによると、"EnableScriptGlobalization プロパティを true に設定すると、グローバル化された JavaScript 関数がカルチャ固有の情報を表示します" とのことです。

カルチャは、ブラウザ、サーバーコード、または Web サイトの構成ファイルで設定できます。例えば、@ Page ディレクティブで Culture, UICulture を "auto" に設定した場合、ASP.NET がリクエスト情報に含まれる Accept-Language ヘッダの内容から判断して、自動的にカルチャを特定してくれます。

なので、EnableScriptGlobalization プロパティが true に設定してあると、「(1) TextBox に入力される日付の形式」は、カルチャが ja-JP の場合は yyyy/MM/dd 形式、en-US の場合は M/d/yyyy となります。

「(2) カレンダーの曜日」も、カルチャが ja-JP の場合は日本語、en-US の場合は英語で表示されます。下の画像はカルチャが en-US の場合のものです。カルチャが ja-JP の場合のもの(上の画像)と比較してみてください。

カルチャが en-US の場合

なお、TextBox に入力される日付の形式は、CalendarExtender コントロールの Format プロパティで明示的に設定できます。当然、EnableScriptGlobalization プロパティの設定より、こちらの方が優先されます。なので、カルチャに依存させないで固定的に日付の形式を設定したい場合は Format="yyyy/MM/dd" のようにすることができます。

以上の対応で、上記の問題の (1) と (2) は解決できます。しかし、「(3) カレンダーのタイトルと今日の日付の表示」は依然として米国形式のままです。これを解決するには、CalendarExtender コントロールの DaysModeTitleFormat, TodaysDateFormat プロパティで書式を指定してやります。

下の画像は、DaysModeTitleFormat="yyyy年M月" TodaysDateFormat="yyyy年M月d日" とした時のものです。

タイトルと今日の日付を日本語形式に

ただし、Format, DaysModeTitleFormat, TodaysDateFormat プロパティで書式を指定してしまうのは、グローバル化と逆行することになる(他のカルチャに対応できなくなる)ので、そうすることが良いのかどうかはよく考えた方がよさそうです。

参考に、上の画像のカレンダーを表示したコードを載せておきます。

<%@ Page Language="C#" Culture="auto" UICulture="auto" %>
<%@ Import Namespace="System.Threading" %>

<%@ Register Assembly="AjaxControlToolkit" 
  Namespace="AjaxControlToolkit" 
  TagPrefix="asp" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  protected void Page_Load(object sender, EventArgs e)
  {
    Label1.Text = "CurrentCulture: " +
        Thread.CurrentThread.CurrentCulture.ToString();
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <asp:ToolkitScriptManager ID="ToolkitScriptManager1" 
    runat="server" 
    EnableScriptGlobalization="True">
  </asp:ToolkitScriptManager>
  <div>
    <asp:Label ID="Label1" runat="server">
    </asp:Label>
    <br />
    <asp:TextBox ID="TextBox1" runat="server">
    </asp:TextBox>
    <asp:CalendarExtender ID="TextBox1_CalendarExtender" 
      runat="server" 
      Enabled="True" 
      TargetControlID="TextBox1"            
      DaysModeTitleFormat="yyyy年M月" 
      TodaysDateFormat="yyyy年M月d日"
      Format="yyyy/MM/dd" >
    </asp:CalendarExtender>
  </div>
  </form>
</body>
</html>

Tags: ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。その後ブログ2を追加し、ここはプログラミング関係、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  July 2022  >>
MoTuWeThFrSaSu
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar