WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

ListView でページ指定

by WebSurfer 2010年11月13日 16:25
ListView でページ指定

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 を参考にしています(参考というよりほぼ丸写しですが)。

Tags: , ,

Paging

DataPager のバグその2

by WebSurfer 2010年10月30日 14:34

先のポスト DataPager のバグその1 に続いて、再び DataPager のバグの話です。なお、このバグも .NET 4 では修正されており、.NET 3.5 のみの問題です。

ListView の中に配置した DataPager の設定にある条件が重なると Stack Overflow を起こします。条件というのは以下の 5 つです。

  1. ListView の LayoutTemplate の中に DataPager を配置
  2. ListView に EmptyDataTemplate を配置
  3. ListView にバインドされるデータの件数が 0
  4. DataPager.QueryStringField を設定(例: QueryStringField="pageNumber")
  5. そのページを、クエリ文字列 ?pageNumber=1 として要求

残念ながら原因は分かりません。(涙)

でも、回避策は簡単で、DataPager を ListView の外に出してしまえばいいのです。件数 0 の場合は ListView の外に DataPager を配置しても、それが表示されることはないです。

または、当然ながら、DataPager.QueryStringField の設定を止めても回避できます。DataPager.QueryStringField を使う理由が、GridView.PageIndex プロパティのようにコードでページを指定したいということであれば、別の手段があります。

その「別の手段」の具体的な方法は、Resetting the Page Index in a ListView が参考になると思います。

Tags:

Paging

DataPager のバグその1

by WebSurfer 2010年10月29日 23:18

.NET 3.5 で ListView コントロールと共に導入された DataPager コントロールには、QueryStringField プロパティ周りにバグがあります。

QueryStringField プロパティというのは、クエリ文字列を利用してページの移動先を指定し、ページの移動に HTTP GET コマンド(デフォルトでは POST)を使用できるようにするためのものです。

例えば、QueryStringField="pageNumber" と設定した場合、ページャーをクリックして指定した移動先のページ番号が 5 であったとすると、URL にクエリ文字列 ?pageNumber=5 を追加して HTTP GET コマンドでそのページを要求するようになります。

MSDN ライブラリ「DataPager.QueryStringField プロパティ」によると "検索エンジンですべてのデータ ページにインデックスが付けられるようにするには、このプロパティを設定すると便利です。" とのことです。

ところが、このページを要求する際に、クエリ文字列のキーに null が含まれる場合(例えば、?pageNumber=5& とすると、& の後に null のキーがあると判断されるようです)、NullReferenceException がスローされるという問題があります。

ページ内でページャーをクリックしているだけなら、自動的に ?pageNumber=x (x は要求するページ番号)というクエリ文字列が URL に追加されて要求がかかるので間違いなく動作しますが、別のページでクエリ文字列を組み立ててそのページを要求する場合、間違って ?pageNumber=x& などとすると例外がスローされます

この問題は、2008 年 7 月に Connect に報告されています。

この報告によると、受信したクエリ文字列のキーに null が含まれていると、ライブラリ内のメソッドの以下の部分で key(String オブジェクト)が null になって NullReferenceException がスローされるということだそうです。これはバグとして次期バージョンで修正されるという話になっていました。

foreach (string key in request.QueryString.AllKeys)
{
  if (... && !key.Equals(queryStringField, 
                StringComparison.OrdinalIgnoreCase))

今日、このページをのぞいてみたら、すでに修正済みというようなことが書いてあります。ということは、少なくとも .NET 4 では修正されているはずです。

ということで、早速試してみました。結果は:

  • .NET 3.5 SP1: ダメでした。NullReferenceException がスローされます。
  • .NET 4: 例外はスローされなかったので、バグは修正されているようです。

というわけで、ASP.NET 3.5 では回避策がまだ必要なようです。上に紹介した Connect のページに回避策も提案されていますので、そちらを参照してください。

Tags:

Paging

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年3月  >>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar