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年11月13日 16:25
GridView や ListView でページングを行っている場合、プログラムで表示するページを指定したいケースがあると思います。
GridView の場合は簡単で、PageIndex プロパティを用いてページの指定ができます。
ところが、ListView には、GridView の PageIndex プロパティのような、表示するページを指定できるプロパティがありません。
これは、GirdView にはページング機能が統合されているのに対し、ListView そのものにはページング機能は実装されていないからです。
通常、ListView でページングを行うには、DataPager コントロールを用います。これを利用すれば、GridView.PageIndex プロパティと同様に、ListView でもプログラムで表示するページを指定することができます。
以下に、ListView において、プログラムで表示するページを指定する例を書いておきます。
まず、DataPager フィールドに NumericPagerField クラスを実装する必要があります。その HandleEvent メソッドを利用します。
HandleEvent メソッドは、引数の CommandEventArgs オブジェクトの CommandName プロパティの値を見て、それにページ番号が指定されている場合、対応するページに移動させます。
上の画像のサンプルのコードは以下の通りです。TextBox にページ番号を入力してボタンをクリックすると、指定したページに飛びます。
<%@ Page Language="C#" %>
<!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 Button1_Click(object sender, EventArgs e)
{
int page = 0;
if (Int32.TryParse(TextBox1.Text, out page))
{
page -= 1;
}
CommandEventArgs commandEventArgs =
new CommandEventArgs(page.ToString(), "");
DataPager dp =
(DataPager)ListView1.FindControl("DataPager1");
NumericPagerField numericPagerField =
dp.Fields[2] as NumericPagerField;
if (numericPagerField != null)
{
numericPagerField.HandleEvent(commandEventArgs);
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style type="text/css">
table.style1
{
border-style: solid;
border-width: 2px;
border-color: Black;
text-align: center;
border-collapse: collapse;
}
table.style1 th
{
border-style: solid;
border-width: 2px 1px 2px 1px;
border-color: Black;
background-color: #6699FF;
color: #FFFFFF;
}
table.style1 td
{
border-style: solid;
border-width: 1px;
border-color: Black;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
Page:
<asp:TextBox ID="TextBox1" runat="server">
</asp:TextBox>
<asp:Button ID="Button1"
runat="server"
Text="Go"
OnClick="Button1_Click" />
<hr />
<asp:ObjectDataSource ID="ObjectDataSource1"
runat="server"
EnablePaging="True"
SelectCountMethod="GetNumberOfMessages"
SelectMethod="GetDataByIndex"
TypeName="OrdersDataSetTableAdapters.OrdersTableAdapter">
<SelectParameters>
<asp:Parameter Name="employeeid" DefaultValue="-1" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:ListView ID="ListView1"
runat="server"
DataKeyNames="OrderID"
DataSourceID="ObjectDataSource1">
<LayoutTemplate>
<table runat="server">
<tr runat="server">
<td runat="server">
<table ID="itemPlaceholderContainer"
runat="server"
class="style1">
<tr runat="server">
<th id="Th1" runat="server">
OrderID</th>
<th id="Th2" runat="server">
CustomerID</th>
<th id="Th3" runat="server">
OrderDate</th>
<th id="Th4" runat="server">
Freight</th>
<th id="Th5" runat="server">
ShipCountry</th>
</tr>
<tr ID="itemPlaceholder"
runat="server">
</tr>
</table>
</td>
</tr>
<tr runat="server">
<td runat="server">
<asp:DataPager ID="DataPager1"
runat="server"
PageSize="10">
<Fields>
<asp:TemplatePagerField>
<PagerTemplate>
<b>
Page
<asp:Label runat="server"
ID="CurrentPageLabel"
Text="<%# Container.TotalRowCount>0 ? (Container.StartRowIndex / Container.PageSize) + 1 : 0 %>" />
of
<asp:Label runat="server"
ID="TotalPagesLabel"
Text="<%# Math.Ceiling ((double)Container.TotalRowCount / Container.PageSize) %>" />
(
<asp:Label runat="server"
ID="TotalItemsLabel"
Text="<%# Container.TotalRowCount%>" />
records)
<br />
</b>
</PagerTemplate>
</asp:TemplatePagerField>
<asp:NextPreviousPagerField
ButtonType="Button"
ShowFirstPageButton="true"
ShowNextPageButton="false"
ShowPreviousPageButton="false" />
<asp:NumericPagerField
PreviousPageText="< Prev 5"
NextPageText="Next 5 >"
ButtonCount="5" />
<asp:NextPreviousPagerField
ButtonType="Button"
ShowLastPageButton="true"
ShowNextPageButton="false"
ShowPreviousPageButton="false" />
</Fields>
</asp:DataPager>
</td>
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="OrderIDLabel"
runat="server"
Text='<%# Eval("OrderID") %>' />
</td>
<td>
<asp:Label ID="CustomerIDLabel"
runat="server"
Text='<%# Eval("CustomerID") %>' />
</td>
<td>
<asp:Label ID="OrderDateLabel"
runat="server"
Text='<%# Eval("OrderDate", "{0:yyyy/MM/dd}") %>' />
</td>
<td>
<asp:Label ID="FreightLabel"
runat="server"
Text='<%# Eval("Freight", "${0:N2}") %>' />
</td>
<td>
<asp:Label ID="ShipCountryLabel"
runat="server"
Text='<%# Eval("ShipCountry") %>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
なお、上記は Resetting the Page Index in a ListView を参考にしています(参考というよりほぼ丸写しですが)。
by WebSurfer
2010年11月8日 21:19
先の記事 UpdatePanel へのトリガ追加 で、AsyncPostBackTrigger をプログラムで追加する話を書きましたが、MSDN ライブラリの AsyncPostBackTrigger クラス の説明によると、それはサポートされていないのだそうです。無知でした。(汗)
MSDN ライブラリの説明に書かれているように、RegisterAsyncPostBackControl メソッド を使って書き換えました。
コードは以下のとおりです。先の記事のサンプルから C# のコードの部分を書き換えただけです。こんなに簡単だったとは、以前の苦労はなんだったんだろうという感じです。(笑)
<%@ Page Language="C#" %>
<!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)
{
LinkButton lb =
(LinkButton)DetailsView1.FindControl("LinkButton1");
if (lb != null)
{
ScriptManager1.RegisterAsyncPostBackControl(lb);
}
}
protected void LinkButton1_Click(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToString();
UpdatePanel2.Update();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>AsyncPostBackTrigger を動的に設定</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:MyDB %>"
SelectCommand="SELECT [id], [name], [price] FROM [table]" >
</asp:SqlDataSource>
<asp:Button ID="DummyButton"
runat="server"
style="display: none;" />
<h2>AsyncPostBackTrigger を動的に設定</h2>
<h3>DetailsView</h3>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:DetailsView ID="DetailsView1"
runat="server"
AutoGenerateRows="False"
DataKeyNames="id"
DataSourceID="SqlDataSource1"
EnableModelValidation="True"
AllowPaging="True" Width="250px">
<Fields>
<asp:BoundField DataField="id"
HeaderText="id"
InsertVisible="False"
ReadOnly="True"
SortExpression="id" />
<asp:BoundField DataField="name"
HeaderText="name"
SortExpression="name" />
<asp:BoundField DataField="price"
HeaderText="price"
SortExpression="price" />
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="LinkButton1"
runat="server"
CausesValidation="False"
Text="Show Current Time"
OnClick="LinkButton1_Click">
</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
</ContentTemplate>
</asp:UpdatePanel>
<hr />
<h3>Time</h3>
<asp:UpdatePanel ID="UpdatePanel2"
runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="Label1"
runat="server"
Text="[time]" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
------------ 2010/3/26 追記 ------------
どうも上記の例は適切ではなかったです。
RegisterAsyncPostBackControl メソッドは「同期ポストバックではなく非同期ポストバックを実行できるように、Web サーバーコントロールをトリガとして登録」するものであって、ある特定の UpdatePanel の Trigger コレクションに AsyncPostPackTrigger を登録するものではないです。従って、部分更新を行うには、LinkButton.Click のイベントハンドラで当該 UpdatePanel の Update メソッドを実行する必要があります。
上記の例では、LinkButton が配置された DetailsView は UpdatePanel1 に含まれているので、RegisterAsyncPostBackControl で非同期ポストバックのトリガとして登録する必要はなく、単純に Click のイベントのハンドラ(LinkButton1_Click メソッド)で UpdatePanel2 の Update メソッドを実行すれば済みました。
これは 先のシナリオ でも同じです。LinkButton が UpdatePanel 内にない場合を例にすべきでした。(汗)