by WebSurfer
2013年12月12日 21:24
先の記事 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>