WebSurfer's Home

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

table のヘッダ、列を固定

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 行にした場合にも適用できるかどうか試してみました。結果は下の画像のように期待通り表示されました。

table のヘッダ(tr 要素)を固定

ただし、ヘッダーだけでなく列も固定すると、何故か固定した部分の 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>
・・・後略・・・

Tags: , ,

ASP.NET

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

GridView, ListView に合計表示

by WebSurfer 2010年11月7日 19:04
ListView に合計を表示

GirdView や ListView で、ある列の合計金額を計算して、フッターなどに表示したいというケースが時々あります。備忘録として、その例を書いておきます。

GridView は「行」(GridViewRow クラス)で構成されているのに対して、ListView は「項目」(ListViewItem クラス)で構成されているという違いがありますが、基本的な方法は行/項目にデータがバインドされるときのイベントを利用して、値を取得して合計していくという操作は同じだと思います。

GridView, ListView どちらの場合も、データソースコントロールが取得してバインドするデータが DataTable の場合(デフォルト)は、DataItem プロパティを使って DataRowView を取得できますので、それから各行/項目の値を取得するのがよさそうです。

合計した結果を書き込むところが、ちょっと違います。

GridView では、フッターでも RowDataBound イベントが発生します。そのイベントハンドラでデータ行かフッター行かが判定でき、フッター行の場合に合計をフッターに書き込むことができます。

ShowFooter="True" として、その中の TableCell の Text プロパティに書き込む例は以下の通りです。

decimal total = 0m;
    
protected void GridView1_RowDataBound(object sender, 
  GridViewRowEventArgs e)
{        
  if (e.Row.RowType == DataControlRowType.DataRow)
  {
    DataRowView drv = (DataRowView)e.Row.DataItem;
    total = total + (decimal)drv["Freight"];
  }
  else if (e.Row.RowType == DataControlRowType.Footer)
  {
    e.Row.Cells[1].Text = "Freight Total";
    e.Row.Cells[2].Text = String.Format("${0:N2}", total);
  }        
}

ListView では、合計の取得は ItemDataBound イベントハンドラで可能ですが、GridView の時のようにフッター行に合計結果を書き込むことはできません。

LayoutTemplate にフッターの行を追加して Label を配置し、その Text プロパティに書き込むことになります。そのタイミングは、ListView.DataBound イベントがよさそうです。

上の画像を出力した ListView のコードを以下にアップしておきます。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  decimal total = 0m;
    
  protected void ListView1_ItemDataBound(object sender, 
      ListViewItemEventArgs e)
  {
    if (e.Item.ItemType == ListViewItemType.DataItem)
    {
      ListViewDataItem lvdi = (ListViewDataItem)e.Item;
      DataRowView drv = (DataRowView)lvdi.DataItem;
      total = total + (decimal)drv["Freight"];
    }
  }

  protected void ListView1_DataBound(object sender, EventArgs e)
  {
    Label label = (Label)ListView1.FindControl("totalLabel");
    label.Text = String.Format("${0:N2}", total);
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>Show Total in ListView</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;        
    }
        
    .footer
    {
      background-color: #CCFFFF;
    }  
  </style>

</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h3>Alfreds Futterkiste</h3>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand="SELECT [OrderID], [OrderDate], [Freight] 
        FROM [Orders] 
        WHERE [CustomerID]='ALFKI'">            
    </asp:SqlDataSource>
    <asp:ListView ID="ListView1" 
      runat="server" 
      DataKeyNames="OrderID" 
      DataSourceID="SqlDataSource1" 
      EnableModelValidation="True" 
      OnItemDataBound="ListView1_ItemDataBound" 
      OnDataBound="ListView1_DataBound">
      <ItemTemplate>
        <tr>
          <td>
            <asp:Label ID="OrderIDLabel" 
              runat="server" 
              Text='<%# Eval("OrderID") %>' />
          </td>
          <td>
            <asp:Label ID="OrderDateLabel" 
              runat="server" 
              Text='<%# Eval("OrderDate", "{0:yyyy/MM/dd}") %>' />
          </td>
          <td style="text-align: right;">
            <asp:Label ID="FreightLabel" 
              runat="server" 
              Text='<%# Eval("Freight", "${0:N2}") %>' />
          </td>
        </tr>
      </ItemTemplate>
      <LayoutTemplate>
        <table ID="itemPlaceholderContainer" 
          runat="server" 
          class="style1">
          <tr runat="server">
            <th runat="server">
              OrderID</th>
            <th runat="server">
              OrderDate</th>
            <th runat="server">
              Freight</th>
          </tr>
          <tr ID="itemPlaceholder" runat="server">
          </tr>
          <tr class="footer">
            <td></td>
            <td>Freight Total</td>
            <td style="text-align: right;">
              <asp:Label ID="totalLabel" runat="server" /></td>
          </tr>
        </table>                        
      </LayoutTemplate>
    </asp:ListView>
  </div>
  </form>
</body>
</html>

Tags: ,

ASP.NET

About this blog

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

Calendar

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

View posts in large calendar