by WebSurfer
2010年11月14日 17:42
Calendar コントロールに CheckBox を配置して、それにチェックを入れた日付をポストバックしてサーバー側で取得するサンプルです。
CheckBox にチェックを入れる/外すたびにポストバックして、チェックを入れた/外した日付を ViewState に追加/削除し、Show selected dates ボタンクリックでチェックが入っている日付を Label に表示します。
「チェックを入れる/外すたびにポストバック」というのがちょっとわずらわしい感じですね。(汗)
でも、月をまたがって日付にチェックを入れる(例えば、1 月 15 日と 3 月 15 日にチェックを入れる)場合も対応できるようにするには、この方法しか思いつかないです。
チェックを入れる/外すたびにいちいちポストバックしないでもすむ方法を考え付いたら、別途記事を書きます・・・が、期待はしないでください。(笑)
2013/12/12 追記:今さらながらですが、チェックを入れる/外すたびにいちいちポストバックしないでもすむサンプルも作ってみました。CheckBox 付き Calendar(その2)を見てください。月を移動する時、ちょっと(かなり?)重い感じです。(汗)
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Implements Interface="System.Web.UI.IPostBackEventHandler" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected List<DateTime> checkedDates = new List<DateTime>();
protected void Calendar1_DayRender(object sender, DayRenderEventArgs e)
{
CheckBox cb = new CheckBox();
cb.ID = e.Day.Date.ToShortDateString();
string script =
Page.ClientScript.GetPostBackEventReference(this, cb.ID);
cb.Attributes.Add("onclick", script);
foreach (DateTime day in checkedDates)
{
if (e.Day.Date == day)
{
cb.Checked = true;
break;
}
cb.Checked = false;
}
e.Cell.Controls.Add(cb);
}
public void RaisePostBackEvent(string eventArgument)
{
foreach (DateTime day in checkedDates)
{
if (eventArgument == day.ToShortDateString())
{
checkedDates.Remove(DateTime.Parse(eventArgument));
ViewState["CheckedDates"] = checkedDates;
return;
}
}
checkedDates.Add(DateTime.Parse(eventArgument));
ViewState["CheckedDates"] = checkedDates;
}
protected void Page_Load(object sender, EventArgs e)
{
object obj = ViewState["CheckedDates"];
if (obj != null)
{
checkedDates = (List<DateTime>)obj;
}
}
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>
</head>
<body>
<form id="form1" runat="server">
<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>
------------ 2010/4/24 追記 ------------
この記事で紹介したコードを実際に動かして試せるよう 実験室 にアップしました。興味のある方は試してみてください。
by WebSurfer
2010年5月23日 21:56
ウィジェットのカレンダーは、デフォルトでは左の写真のように、(1) 月曜日から始まる、(2) 曜日が二文字になる、(3) タイトルが "5月 2010" のようになります。
日本人にはあまりなじみのない表示で、イマイチ気に入らないので、修正してみました。
修正した結果がウィジェット(左サイドのパネル)の中に表示されているカレンダーです。
上記 (1) および (2) の原因は、\widgets\Calendar\widget.ascx で PostCalendar(Calendar コントロールを継承したカスタムコントロール)の
FirstDayOfWeek, DayNameFormat プロパティがそれぞれ Monday, FirstTwoLetters となっているからです。
それを直接書き換えて、Sunday, FirstLetter とすれば (1), (2) の問題は解決します。
でも、国際化対応を考えて(笑)、ブラウザの言語設定が ja-JP または ja の時のみ対応するようにしました。
具体的には、\widgets\Calendar\widget.ascx.cs の LoadWidget メソッドに以下のコードを追加しました。
System.Globalization.CultureInfo ci =
System.Threading.Thread.CurrentThread.CurrentUICulture;
if (ci.Name == "ja-JP" || ci.Name == "ja")
{
this.PostCalendar1.DayNameFormat = DayNameFormat.FirstLetter;
this.PostCalendar1.FirstDayOfWeek = FirstDayOfWeek.Sunday;
}
そうすると、カレンダーの表示幅が狭くなってしまうので、\widgets\Calendar\widget.ascx で PostCalendar.Width プロパティを設定して調整しました。
上記 (3) の原因は、\App_Code\Controls\PostCalendar.cs でタイトル行をレンダリングする時 VisibleDate.ToString("MMMM yyyy") としているからです。
その部分を以下のように変更しました。
//writer.Write("</td><td style=\"text-align:center;width:100px\">" +
// VisibleDate.ToString("MMMM yyyy") +
// "</td><td align=\"right\">");
// 上記のコードを以下のように変更
System.Globalization.CultureInfo ci =
System.Threading.Thread.CurrentThread.CurrentUICulture;
if (ci.Name == "ja-JP" || ci.Name == "ja")
{
writer.Write("</td><td style=\"text-align:center;width:100px\">" +
VisibleDate.ToString("yyyy年M月") +
"</td><td align=\"right\">");
}
else
{
writer.Write("</td><td style=\"text-align:center;width:100px\">" +
VisibleDate.ToString("MMMM yyyy") +
"</td><td align=\"right\">");
}
ウィジェットのカレンダーの中にある "View posts in large calendar" というリンクをクリックすると大きなカレンダーが表示されるのですが、
それには上記 (1), (2), (3) の問題はありません。
何故なら、FirstDayOfWeek, DayNameFormat プロパティはデフォルトになっており、
タイトル行は Calendar コントロール自体ものを表示(ShowTitle プロパティを true に設定)しているからです。
ウィジェットのカレンダーの方で、わざわざデフォルトを変更しているのは何か理由があって、それをいじると予期せぬ副作用があるかもしれませんので、しばらく注意して様子を見たいと思っています。