WebSurfer's Home

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

GridView, ListView で特定の行をハイライト

by WebSurfer 2016年10月13日 23:35

GridView, ListView でデータを一覧表示する際、それにデータバインドされたデータソースに含まれる各行の特定の列のデータの値を調べ、その値に応じて当該行をハイライトする方法について書きます。

元は MSDN フォーラムのスレッド「ListViewでの一覧表示で、取得したデータに応じて背景色を変えたい」での話です。

そのスレッドで自分が回答したことなのですが、忘れかけていたので自分のブログに備忘録として書いておくことにしました。また、ついでに GridView での実装例も書いておきます。

このブログの別の記事「GridView, ListView に合計表示」のコードをベースにしていますので、そちらも見てください。

その記事では、Microsoft が提供するサンプルデータベース Northwind の Orders というテーブルのレコードのうち、[CustomerID] が ALFKI という顧客の注文の [OrderID], [OrderDate], [Freight] フィールド一覧を表示しています。

Orders テーブルには出荷日を示す [ShippedDate] というフィールドが含まれています。ここでは、[ShippedDate] を調べて、ある日付より後に出荷されたレコードの行の背景色をハイライトしてみます。なお、ListView / GridView には [ShippedDate] フィールドは表示しません。

ListView での例

以下の画像は 1998/1/1 より後に出荷された注文のレコードをハイライトしたものです。

ListView

紹介した MSDN フォーラムのスレッドで書いたとおりですが、上のように表示するための具体的な方法を以下に書きます。

  1. SqlDataSource の SELECT クエリに [ShippedDate] を追加します。
  2. ListView の ItemTemplate 内の tr 要素をサーバーコントロールに変更して id を付与します。具体的には runat="server" id="datarow" という 2 つの属性を追加します(id 名は任意)。
  3. 例えば、1998/1/1 より後に出荷されたレコードを黄色でハイライトする場合、[ShippedDate] が 1998/1/1 より後のアイテムの中から FindControl メソッドで上記 2 でサーバーコントロールにした tr 要素を探し、それに style 属性を追加します。コードは以下のようになります。
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"];

    // 以下が追加した部分
    DateTime date = new DateTime(1998, 1, 1, 0, 0, 0);
    if ((DateTime)drv["ShippedDate"] > date)
    {
      HtmlControl tr = (HtmlControl)lvdi.FindControl("datarow");
      if (tr != null)
      {
        tr.Attributes.Add("style", "background-color:yellow;");
      }
    }
  }
}

GridView での例

上の ListView の場合と同様に、1998/1/1 より後に出荷された注文のレコードをハイライトしたものです。

GridView

上のように表示するための具体的な方法は以下の通りです。

  1. SqlDataSource の SELECT クエリに [ShippedDate] を追加します。(ListView の場合と同様)
  2. ListView の場合とは異なり、GridView のコードには手を加える必要はありません。GridView の RowDataBound イベントで GridViewRow を取得し、それの CssClass プロパティにスタイルを設定できますので。
  3. 上の ListView の場合と同様に、1998/1/1 より後に出荷されたレコードを黄色でハイライトする場合、[ShippedDate] を調べて 1998/1/1 より後であれば、当該行の GridViewRow オブジェクトを取得し、その CssClass プロパティを設定します。コードは以下のようになります。
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"];

    // 以下が追加した部分
    DateTime date = new DateTime(1998, 1, 1, 0, 0, 0);
    if ((DateTime)drv["ShippedDate"] > date)
    {
      e.Row.CssClass = "style1";
    }
    // ここまで
  }
  else if (e.Row.RowType == DataControlRowType.Footer)
  {
    e.Row.Cells[1].Text = "Freight Total";
    e.Row.Cells[2].Text = String.Format("${0:N2}", total);

    e.Row.Cells[1].ColumnSpan = 2;
    e.Row.Cells.RemoveAt(0);            
  }        
}

e.Row.CssClass = "style1"; のところの style1 は別途定義してソースに追加してください。インラインで <title> 要素の下に書くなら以下のようにします。

<style type="text/css">
    .style1
    {
        background-color: yellow;
    }
</style>

Tags: , ,

ASP.NET

GridView に overflow 適用

by WebSurfer 2015年11月10日 14:04

GridView の列に長い文字列を入れると、下の画像の「制限しない場合」のように文字列の長さに応じて列の幅が広がっていってしまいます。

それを「overflow:hidden で制限」のように、CSS の overflow を使って決まった範囲内に制限する方法について書きます。(テキストが領域をこえた場合に省略記号「…」を表示することもできます。詳しくはこの記事の下の方の 2015/11/12 追記を見てください)

GridView に overflow 適用

ASP.NET が GridView を html コードにレンダリングすると table, tr, th, td 要素になります。BoundField を使うと文字列は td 要素の中に直接配置されます。

td 要素はブロックレベル要素ではないのでそれに直接 overflow は適用できません。なので、td 要素の中に div 要素を 配置しそれに overflow 他のスタイルを適用した上で div 要素内に文字列を入れるのがよさそうです。

クライアント側だけで JavaScript を使っても可能ですが、ASP.NET のコードで対応した方が簡単そうです。

具体的には、当該列を TemplateField に変換し、それに div 要素を配置して overflow 他のスタイルを適用、div 要素の中に Literal コントロールを配置してその Text プロパティをデータバインドします。

そのコード例は以下の通りで、これを実行すると上の画像の結果になります。

<%@ 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">

  protected void Page_Load(object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      // データソースとして DataTable を作成。
      DataTable dt = new DataTable();
      DataRow dr;

      dt.Columns.Add(new DataColumn("id", typeof(Int32)));
      dt.Columns.Add(
          new DataColumn("description", typeof(string)));

      dr = dt.NewRow();
      dr["id"] = 1;
      dr["description"] = "グリッドビューはデータソースの"+ 
                          "値を表に表示します。";
      dt.Rows.Add(dr);

      dr = dt.NewRow();
      dr["id"] = 2;
      dr["description"] = "The GridView displays the " + 
                      "values of a data source in a table.";
      dt.Rows.Add(dr);

      // 上で作成した DataTable を GridView にバインド。
      GridView1.DataSource = dt;
      GridView1.DataBind();

      GridView2.DataSource = dt;
      GridView2.DataBind();
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>GirdView に overflow 適用</title>
  <style type="text/css">
    div.style1
    {
      width: 150px;
      height: 1.1em;
      overflow: hidden;
    }
  </style>
</head>
<body>
  <form id="form1" runat="server">
  <h2>制限しない場合</h2>
  <asp:GridView ID="GridView1" runat="server">
  </asp:GridView>

  <h2>overflow:hidden で制限</h2>
  <asp:GridView ID="GridView2" 
    runat="server" 
    AutoGenerateColumns="False">
    <Columns>
      <asp:BoundField DataField="id" HeaderText="id" />
      <asp:TemplateField HeaderText="description">
        <ItemTemplate>
          <div class="style1">
            <asp:Literal ID="Literal1" 
              runat="server" 
              Text='<%# Eval("description") %>'>
            </asp:Literal>
          </div>
        </ItemTemplate>
      </asp:TemplateField>
    </Columns>
  </asp:GridView>
  </form>
</body>
</html>

------ 2015/11/12 追記 ------

テキストが領域をこえた場合に「…」を表示する text-overflow:ellipsis はもともと IE の独自拡張だそうですが、最近は他のブラウザでも取り入れられているようです。下の画像は、自分の環境 Vista SP2 32-bit で、Opera 12.17 で試した結果です。

text-overflow:ellipsis 適用

IE9, Chrome 46.0.2490.86 m, Firefox 42.0, Safari 5.1.7 でも同様に text-overflow:ellipsis は有効でした。(古いバージョン、その他のブラウザは未確認です) 上の画像の例ではスタイルを以下のように変更しています。
<style type="text/css">
    div.style1
    {
        width: 150px;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }
</style>

Tags: ,

ASP.NET

DropDownList での NULL の処置

by WebSurfer 2015年10月23日 17:19

下の画像のように、GridView などでデータベースの更新操作を行う際 DropDownList を利用してユーザー入力に便宜を図ることがあると思います。その時、NULL を DropDownList でどう対処するかという話を書きます。

GridView 上の DropDownList

ここで紹介する例には Microsoft が提供している Northwind サンプルデータベースの Products テーブルと Categories テーブルを使用しています。

Products テーブルの中の ProductName, CategoryID フィールドを GridView 上で更新する際、CategoryID の列に DropDownList を表示するようにします。

DropDownList には、ユーザーが見ても何だか分からない数字 (CategoryID) を表示するのでははなくて、ユーザーが読んで理解できる名前 (CategoryName) を Categories テーブルから取得して表示します。

Products テーブルの CategoryID には以下のような外部キー制約がかかっていますので、Categories テーブルの CategoryID の値(Northwind サンプルデータベースでは 1 から 8)以外のものは入力できません。

ALTER TABLE [dbo].[Products]  
  ADD CONSTRAINT [FK_Products_Categories] 
  FOREIGN KEY([CategoryID])
  REFERENCES [dbo].[Categories] 
  ([CategoryID])

ただし、NULL は許可されていますので、1 から 8 以外に NULL が入っていることがあります。また、更新の際に NULL を入力したいというケースもあるかもしれません。

先の記事 GridView 上の DropDownList に ToolTip でも同様に DropDownList を使用していますが、そこでは NULL 対応は考えていませんでした。それを以下ように修正して NULL に対応します。

  1. SELECT クエリで INNER JOIN 句に替えて LEFT OUTER JOIN 句を使い CategoryID が NULL のレコードも抽出する。
  2. DropDownList で AppendDataBoundItems="True" とし、以下のような NULL 用の ListItem を追加する。

    <asp:ListItem Value="">NULL</asp:ListItem>

    Value は空白("")にしてください。DropDownList に表示される文字列 NULL は任意のものに変えていいです。データベース上での NULL と ASP.NET コントロール上での空白("")の変換は、ASP.NET の組み込み機能を利用します。その機能についての説明は MSDN ライブラリの記事データ ソース コントロールを使用した、データベースの Null 値の処理を見てください。

具体的なコードは以下の通りです。(分かりやすくするため、先の記事 GridView 上の DropDownList に ToolTip のコードの ToolTip を設定する部分は省いています)

<%@ 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>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:SqlDataSource ID="SqlDataSource1" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind2 %>" 
      SelectCommand=
        "SELECT TOP 10 
        p.[ProductID], p.[ProductName], 
        p.[CategoryID], c.[CategoryName] 
        FROM [Products] AS p 
        LEFT OUTER JOIN [Categories] AS c 
        ON p.[CategoryID] = c.[CategoryID]
        ORDER BY p.[ProductID]" 
      UpdateCommand=
        "UPDATE [Products] 
        SET [ProductName] = @ProductName, 
        [CategoryID] = @CategoryID 
        WHERE [ProductID] = @ProductID">
      <UpdateParameters>
        <asp:Parameter Name="ProductID" Type="Int32" />
        <asp:Parameter Name="ProductName" Type="String" />
        <asp:Parameter Name="CategoryID" Type="Int32" />
      </UpdateParameters>
    </asp:SqlDataSource>

    <asp:SqlDataSource ID="SqlDataSource2" 
      runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind2 %>" 
      SelectCommand=
        "SELECT [CategoryID], [CategoryName], [Description] 
        FROM [Categories]">
    </asp:SqlDataSource>
        
    <asp:GridView ID="GridView1" 
      runat="server" 
      AutoGenerateColumns="False" 
      DataKeyNames="ProductID" 
      DataSourceID="SqlDataSource1">
      <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="ProductID" 
          HeaderText="ID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" 
          HeaderText="Product Name" 
          SortExpression="ProductName" />
        <asp:TemplateField HeaderText="Category" 
          SortExpression="CategoryName">
          <EditItemTemplate>                        
            <asp:DropDownList ID="DropDownList1" 
              runat="server" 
              DataSourceID="SqlDataSource2" 
              DataTextField="CategoryName" 
              DataValueField="CategoryID" 
              SelectedValue='<%# Bind("CategoryID") %>' 
              AppendDataBoundItems="True">
              <asp:ListItem Value="">NULL</asp:ListItem>
            </asp:DropDownList>
          </EditItemTemplate>
         <ItemTemplate>
            <asp:Label ID="Label1" 
              runat="server" 
              Text='<%# Bind("CategoryName") %>'>
            </asp:Label>
          </ItemTemplate>
        </asp:TemplateField>
      </Columns>
    </asp:GridView>
  </div>
  </form>
</body>
</html>

Tags: , ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2017年8月  >>
303112345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar