by WebSurfer
2012年3月17日 17:03
ユーザーが ListView 上の CheckBox にチェックを入れて複数の項目を選択後、ポストバックしてサーバー側で選択された項目を取得するという例です。
特に難しいことではないのですが、GridView と違って、ListView の場合はあまり例が見つからないので、忘れないように書いておきます。
ListView は「項目」(ListViewItem オブジェクト)で構成されており、そのコレクションは Items プロパティで取得できます。
後はループを回して、ListViewItem オブジェクトの中から FindControl メソッドで CheckBox オブジェクトを探し、チェックがついているかどうかを調べることができます。
そのサンプルコードは以下の通りです。
<%@ 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">
// ListView に CheckBox を追加。ポストバックして、
// ユーザーがチェックを入れた項目をサーバー側で取得。
protected void Button1_Click(object sender, EventArgs e)
{
string ids = "";
for (int i = 0; i < ListView1.Items.Count; i++ )
{
ListViewItem item = ListView1.Items[i];
CheckBox cb = (CheckBox)item.FindControl("CheckBox1");
if (cb != null)
{
if (cb.Checked == true)
{
ids += ListView1.DataKeys[i].Value.ToString() + " ";
}
}
}
Label1.Text = "Selected Products: " + ids;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ListView と CheckBox</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1"
runat="server"
Text="PostBack"
OnClick="Button1_Click" />
<asp:SqlDataSource ID="SqlDataSource1"
runat="server"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand=
"SELECT [ProductID], [ProductName], [UnitPrice]
FROM [Products] WHERE [CategoryID]=1">
</asp:SqlDataSource>
<asp:ListView ID="ListView1"
runat="server"
DataKeyNames="ProductID"
DataSourceID="SqlDataSource1">
<EmptyDataTemplate>
<table id="Table1" runat="server" style="">
<tr>
<td>
データは返されませんでした。</td>
</tr>
</table>
</EmptyDataTemplate>
<ItemTemplate>
<tr style="">
<td>
<asp:CheckBox ID="CheckBox1"
runat="server" />
</td>
<td>
<asp:Label ID="ProductIDLabel"
runat="server"
Text='<%# Eval("ProductID") %>' />
</td>
<td>
<asp:Label ID="ProductNameLabel"
runat="server"
Text='<%# Eval("ProductName") %>' />
</td>
<td>
<asp:Label ID="UnitPriceLabel"
runat="server"
Text='<%# Eval("UnitPrice") %>' />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="Table2" runat="server">
<tr id="Tr1" runat="server">
<td id="Td1" runat="server">
<table ID="itemPlaceholderContainer"
runat="server"
border="0"
style="">
<tr id="Tr2" runat="server" style="">
<th id="Th1" runat="server">
Select</th>
<th id="Th2" runat="server">
ProductID</th>
<th id="Th3" runat="server">
ProductName</th>
<th id="Th4" runat="server">
UnitPrice</th>
</tr>
<tr ID="itemPlaceholder" runat="server">
</tr>
</table>
</td>
</tr>
<tr id="Tr3" runat="server">
<td id="Td2" runat="server" style="">
</td>
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</div>
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
by WebSurfer
2011年1月23日 15:17
2017/8/16 注記追加
Windows 10 IE11 では Quirks モード(IE5 相当)にしても expression 関数が働かないようで、テーブルのヘッダ・列は固定されませんのでご注意ください。この記事はもう意味がないかもしれませんが、せっかく書いたので残しておきます。
MSDN フォーラムなどで、IE の互換モード(正確には Quirks モードという IE5 以前のレンダリングエンジン)で動く table のヘッダ(tr 要素)を固定する "Freezing" という名前の css に関する質問を時々見かけます。
これは IE 独自拡張の expression 関数を使ったものですが、ListView でヘッダーを 2 行にした場合にも適用できるかどうか試してみました。結果は下の画像のように期待通り表示されました。
ただし、ヘッダーだけでなく列も固定すると、何故か固定した部分の border の幅が広くなってしまい、それを解決する方法が見つかっていないのが悔しいところですが。(汗)
上の画像を作ったコードは以下の通りです。Microsoft が提供している Northwind サンプルデータベースの Products テーブルを使用しています。
<%@ 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">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<%--Quirks モードに設定--%>
<meta http-equiv="X-UA-Compatible" content="IE=5" />
<style type="text/css">
.FreezingHeader
{
z-index: 10;
position: relative;
top: expression(this.offsetParent.scrollTop);
background-color: #0000cc; /* ヘッダ部分の border の色 */
}
.FreezingCol
{
z-index: 1;
left: expression(document.getElementById("freezingDiv").scrollLeft);
position: relative;
background-color: white;
}
#freezingDiv
{
overflow: auto;
width: 400px;
height: 300px;
}
table.style1
{
border-style: none; /* 指定するとスクロールでずれる */
text-align: center;
border-collapse: collapse;
}
table.style1 th
{
border-style: solid;
border-width: 2px;
border-color: #0000cc;
background-color: #6699FF;
color: #FFFFFF;
padding: 5px;
}
table.style1 td
{
border-style: solid;
border-width: 2px;
border-color: #0000cc;
padding: 5px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:Northwind %>"
SelectCommand=
"SELECT [ProductID], [ProductName], [QuantityPerUnit], [UnitPrice], [UnitsInStock]
FROM [Products]">
</asp:SqlDataSource>
<div id="freezingDiv">
<asp:ListView ID="ListView1"
runat="server"
DataKeyNames="ProductID"
DataSourceID="SqlDataSource1"
EnableModelValidation="True">
<ItemTemplate>
<tr>
<td class="FreezingCol">
<asp:Label ID="ProductIDLabel"
runat="server"
Text='<%# Eval("ProductID") %>' />
</td>
<td class="FreezingCol">
<asp:Label ID="ProductNameLabel"
runat="server"
Text='<%# Eval("ProductName") %>' />
</td>
<td>
<asp:Label ID="QuantityPerUnitLabel"
runat="server"
Text='<%# Eval("QuantityPerUnit") %>' />
</td>
<td>
<asp:Label ID="UnitPriceLabel"
runat="server"
Text='<%# Eval("UnitPrice") %>' />
</td>
<td>
<asp:Label ID="UnitsInStockLabel"
runat="server"
Text='<%# Eval("UnitsInStock") %>' />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table ID="itemPlaceholderContainer"
runat="server"
class="style1">
<tr runat="server" class="FreezingHeader">
<th runat="server" colspan="2" class="FreezingCol">
ID and Name</th>
<th runat="server" colspan="3">
Details of Products</th>
</tr>
<tr runat="server" class="FreezingHeader">
<th runat="server" class="FreezingCol">
ProductID</th>
<th runat="server" class="FreezingCol">
ProductName</th>
<th runat="server">
QuantityPerUnit</th>
<th runat="server">
UnitPrice</th>
<th runat="server">
UnitsInStock</th>
</tr>
<tr ID="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
</div>
</form>
</body>
</html>
個人的には IE 専用のハック的な方法と思っていますので、これを実際に使うことはなさそうですが、こういったこともできるということでご参考まで。
------------ 2011/4/29 追記 ------------
上の画像のように固定した部分の border の幅が広くなってしまう問題は、以下のように、class="FreezingCol" を付与した th, td 要素に inline スタイルで border の幅を指定してやることで解決できます。
・・・前略・・・
<ItemTemplate>
<tr>
<td class="FreezingCol" style="border-width: 1 1 1 2;">
<asp:Label ID="ProductIDLabel"
runat="server"
Text='<%# Eval("ProductID") %>' />
</td>
<td class="FreezingCol" style="border-width: 1 1 1 1;">
<asp:Label ID="ProductNameLabel"
runat="server"
Text='<%# Eval("ProductName") %>' />
</td>
・・・中略・・・
</ItemTemplate>
<LayoutTemplate>
<table ID="itemPlaceholderContainer"
runat="server"
class="style1">
<tr runat="server" class="FreezingHeader">
<th runat="server" colspan="2" class="FreezingCol" style="border-width: 2 1 1 2;">
ID and Name</th>
<th runat="server" colspan="3">
Details of Products</th>
</tr>
<tr runat="server" class="FreezingHeader">
<th runat="server" class="FreezingCol" style="border-width: 1 1 1 2;">
ProductID</th>
<th runat="server" class="FreezingCol" style="border-width: 1 1 1 1;">
ProductName</th>
・・・後略・・・
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 を参考にしています(参考というよりほぼ丸写しですが)。