QA@IT

ASP.NET(C#)のGridViewコントロールの行列固定方法について

13620 PV

ASP.NET(C#)のGridViewコントロールの行列固定方法について教えてください。
下記2つのサイトを参考に「Grid.js」と「Grid.css」を使用し、GridViewコントロールの行列の固定を試みています。
http://dalmore.blog7.fc2.com/blog-entry-50.html
http://surferonwww.info/BlogEngine/post/2013/02/04/freezing-header-and-column-of-gridview-by-using-javascript-gridjs.aspx
しかし、この方法でコンテンツページ(asp:Content)内に実装しようとしたときにGridViewが消えてしまいます。
(外枠とスクロールバーのみ表示している状態)
コードは次のようになっています。
[.aspx]

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <script src="../../../../Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script src="../../../../Scripts/Grid.js" type="text/javascript"></script>
    <link href="../../../../Styles/Grid.css" rel="stylesheet" type="text/css" />
    <style type="text/css">
        .fakeContainer
        {
            margin: 0 0 20px;
            border: 1px;
            width: 600px;
            height: 150px;
            overflow: hidden; 
        }
    </style>
    <script type="text/javascript">
        window.onload = function () {            
            $('#GridView3').parent("div").addClass("fakeContainer");            
            $('#GridView3').parent("div").attr("id", "myGrid");
            new Grid("myGrid", {
                srcType: "dom",
                srcData: "GridView3",
                allowClientSideSorting: true,
                fixedCols: 1
            });
        };
    </script>
    <asp:GridView ID="GridView3" runat="server" CellPadding="5" 
        GridLines="Vertical" onrowcreated="GridView3_RowCreated" ClientIDMode="Static" >
        ~略~
        </asp:GridView>
</asp:Content>

[.aspx.cs]

protected void Page_Load(object sender, EventArgs e)
{
     GridView3.AutoGenerateColumns = false;
     GridView3.UseAccessibleHeader = true;
     GridView3.DataSource = データテーブル;
     GridView3.DataBind();
     GridView3.HeaderRow.TableSection = TableRowSection.TableHeader;
}

勉強不足で申し訳ないのですが、解決策を教えていただけないでしょうか。

  • Visual Studio, C#, ASP.NETのバージョンをわかる範囲で教えてください。jQueryのバージョンが古めなので、ひょっとして.NETのバージョンも古いとか? -
  • 調べてみたら、jQuery1.4でも2010年なんですね。なんにせよバージョンわかる範囲でお願いします。 -
  • flied_onionさん、ありがとうございます。
    ・Visual Web Developer 2010 Express
    ・ASP.NET 4.0
    で開発しております。
    -
  • Grid.js は jQuery を使ってません。また、対象は table (thead, tbody は必要ですが)でいいので、ASP.NET のバージョンは重要ではなさそうです。 -
  • 補足ありがとうございます。バージョンはClient ID Modeですね。コントロールにプロパティとして追加されたのは ASP.NET4.0からだったと記憶してましたもので(ページには2.0からでしたっけ)。他の回答のやり取りをみて大丈夫そうとは思いましたが一応聞いてみました。 -

回答

Visual Studio 2010 Professional のテンプレートで作った MasterPage に、ブログのサンプルコードを、内容そのままで、単に分けて入れただけで問題なく動きます。

分け方は以下の通りです。質問者さんのコードとどこが違うか見比べてください。

ちなみに、以下のコードの場合 GridView の ClientID は ContentPlaceHolder1_GridView1 になります。<%=GridView1.ClientID%> で対応してます。

MasterPage3.master.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class MasterPage3 : System.Web.UI.MasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
}

MasterPage3.master

<%@ Master Language="C#" AutoEventWireup="true" 
    CodeFile="MasterPage3.master.cs" Inherits="MasterPage3" %>

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

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h2>MasterPage3.master</h2>
        <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">

        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

193-GridjsInMasterPage.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;

public partial class _193_GridjsInMasterPage : System.Web.UI.Page
{
    // データソース用の DataTable を作成
    protected DataTable CreateDataTable()
    {
        DataTable dt = new DataTable();
        DataRow dr;

        dt.Columns.Add(new DataColumn("ID", typeof(Int32)));
        dt.Columns.Add(new DataColumn("Name", typeof(string)));
        dt.Columns.Add(new DataColumn("Type", typeof(string)));
        dt.Columns.Add(new DataColumn("Price", typeof(Int32)));
        dt.Columns.Add(new DataColumn("Qty", typeof(Int32)));
        dt.Columns.Add(new DataColumn("Amount", typeof(Int32)));
        dt.Columns.Add(new DataColumn("CategoryID", typeof(Int32)));
        dt.Columns.Add(new DataColumn("Note", typeof(string)));
        dt.Columns.Add(new DataColumn("Discontinued", typeof(bool)));
        dt.Columns.Add(new DataColumn("DateTime", typeof(DateTime)));

        for (int i = 0; i < 50; i++)
        {
            dr = dt.NewRow();
            dr["ID"] = i;
            dr["Name"] = "Product Name_" + i.ToString();
            dr["Type"] = "Product Type " + (100 - i).ToString();
            dr["Price"] = 123000 * (i + 1);
            dr["Qty"] = (i + 1) * 20;
            dr["Amount"] = 123000 * (i + 1) * (i + 1);
            dr["CategoryID"] = 100 - i;
            dr["Note"] = "Note_" + i.ToString();
            dr["Discontinued"] = (i % 2 == 0) ? true : false;
            dr["DateTime"] = DateTime.Now.AddDays(i);
            dt.Rows.Add(dr);
        }
        return dt;
    }

    // GridView に上記メソッドで作った DataTable をバインド
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            GridView1.DataSource = CreateDataTable();
            GridView1.DataBind();
        }
    }

    // ソースが DOM の場合、thead, tbody が必要。
    // GridView はデフォルトでは thead, tbody は生成
    // されないので、以下のコードを使って追加する。
    protected void GridView1_RowCreated(
      object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.Header)
        {
            e.Row.TableSection =
              System.Web.UI.WebControls.TableRowSection.TableHeader;
        }
        else if (e.Row.RowType == DataControlRowType.DataRow)
        {
            e.Row.TableSection =
              System.Web.UI.WebControls.TableRowSection.TableBody;
        }
        // フッターがある場合(GridView.ShowFooter が true の場合)は
        // 以下のコードのコメントアウトを解除。
        //else if (e.Row.RowType == DataControlRowType.Footer)
        //{
        //    e.Row.TableSection =
        //      System.Web.UI.WebControls.TableRowSection.TableFooter;
        //}
    }
}

193-GridjsInMasterPage.aspx

<%@ Page Title="" Language="C#" 
    MasterPageFile="~/MasterPage3.master" 
    AutoEventWireup="true" 
    CodeFile="193-GridjsInMasterPage.aspx.cs" 
    Inherits="_193_GridjsInMasterPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
    <script src="/Scripts/Grid.js" type="text/javascript"></script>
    <link href="/css/Grid.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript">
    //<![CDATA[
        window.onload = function () {
            // GridView は div 要素で囲った table を生成するの
            // で、その div 要素を利用する。div 要素に id を付
            // 与して初期サイズを指定する CSS を設定する。
            // div 要素の直下に table がないと、Grid.js による
            // 置き換えがうまくいかない(GridView の table が
            // 残ってしまう)ので注意。
            var tableGridView =
                document.getElementById("<%=GridView1.ClientID%>");
            var parentElement = tableGridView.parentNode;
            parentElement.setAttribute("id", "myGrid");
            parentElement.setAttribute("class", "style1");

            // ソートするために各列のデータ型を指定。デフォルト
            // は string なので、数字などの列がある場合は指定し
            // ないとソート結果が期待通りにならない。
            var gridColSortTypes =
                ["number", "string", "string", "number", "number",
                "number", "number", "string", "none", "date"];

            // GridView (table) の場合、srcType は "dom" に設定。
            // 下のコードの myGrid は table を囲う div 要素の id。
            // SrcData には table の id(GridView の ClientID)を
            // 設定。その他のパラメータ設定は Grid のページ参照。
            // Grid.js は、SrcData に指定された table の DOM を
            // ソースに使って別テーブルを生成し、元の table と置
            // き換える。
            new Grid("myGrid", {
                srcType: "dom",
                srcData: "<%=GridView1.ClientID%>",
                allowGridResize: true,
                allowColumnResize: true,
                allowClientSideSorting: true,
                allowSelections: true,
                allowMultipleSelections: true,
                showSelectionColumn: false,
                colSortTypes: gridColSortTypes,
                fixedCols: 1
            });
        };
    //]]>
    </script>

    <style type="text/css">
        /* テーブルの初期サイズの指定 */
        .style1
        {
            width: 400px;
            height: 360px;
        }    
    </style>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
   <asp:GridView ID="GridView1" 
        runat="server"
        OnRowCreated="GridView1_RowCreated" 
        EnableViewState="False">
    </asp:GridView>
</asp:Content>
編集 履歴 (0)

できました!!
Content側の.aspxの話ですが、今までbodyのContentにjavascriptとcssの記述をしていました。
(そもそもheadのContentは全く書いていませんでした。)
SurferOnWwwさんのコードを見て気付きました。
headのContentを付け足し、その中にjavascriptとcssを移したら動きました。
勉強不足ですみません。本当にありがとうございます。
javascriptとcssは必ず部分に書かなければいけないのでしょうか?

編集 履歴 (0)
  • JavaScript は必ず head に書かなければならないというものではないですが、出てくる順番の問題でうまくいかないころが多いので、レンダリングされた html ソースを見てそのあたりに問題ないか確認されるといいと思います。 -
  • 補足ですが、サイズの大きなライブラリ(Angularjs, knockout.jsなど)をHTMLの最後の方(bodyタグを閉じる手前)において先にページのアウトラインを表示させるような作りにする場合もあります。いずれにしても SuferOnWwwさんの説明されている通り出てくる順番は重要で気をつける必要があります。 -
  • なお、解決された後で、解決の助けになった回答をacceptしてくださいね。 -
  • acceptが遅くなりました。
    SurferOnWwwさん、flied_onionさんありがとうございます。
    非常に助かりました。
    今後javascriptやcssの書く位置を気を付けてみます。
    また色々教えて下さい。
    -
  • 行列固定を行ったことで問題が発生したのでお聞きしたいのですが、この場合は新しく質問しなおした方がよろしいのでしょうか?初めて質問したのですみません。 -

SurferOnWwwさん、ご回答ありがとうございます。
$('#GridView3')やsrcData: "GridView3"の記述についてですが、
下記サイトによるとコントロールのプロパティにClientIDMode="Static"を指定すると
コンテンツ内でもサーバコントロールのIDを取得できるとのことだったのでこのようにしてあります。
http://codezine.jp/article/detail/4853

ClientIDMode="Static"を消し、<%=GridView3.ClientID%>も試しましたが
同じ結果となりました。

編集 履歴 (0)
  • サーバーから送られてきた html ソースを見て id がどうなっているか確認してください。 -
  • idは"GridView3"となっていました。 -
  • 参考にした 2 つめのサイトのコードをそのままコピペして(もちろん .js, .css ファイルのパスは調整してください)試したらどうなりますか? それは自分のブログなので、それから初めてもらえればアドバイスがしやすいです。 -
  • SurferOnWwwさん、勉強させていただいております。
    SurferOnWwwさんのブログ通りに書き直しましたがやはり外枠とスクロールバーのみで中身が表示されません。
    .style1で設定した大きさの外枠です。
    このときGridViewのidは"MainContent_GridView3"となっていました。
    -
  • いきなりマスターページに入れて試さないで順を追って確認していきましょう。まず、私のブログのページのコードをそのまま使ったら期待通りになるのか確認してください。それが確認できてからマスターページを使ってみるようにしないと、ダメな原因を見つけるのが難しいと思います。 -
  • あ、その前に、私のブログの「実際に動かして試すことができるよう 実験室 にアップしました。」とある部分の「実験室」のリンク先を、質問者さんが使っているブラウザで見て、期待通りになるか確認願います。 -
  • コピペのやり方ですが、マウスのポインタをコード表示のエリアに入れると、そのエリアの右上に 4 つアイコンが表示されますので、一番左のアイコン(マウスをポイントすると "view source" と表示されるはず)をクリックしてください。それで表示されるダイアログの中のコードをコピペするのが簡単です。 -
  • 「実験室」サンプルを見させていただきましたが期待通りに動作になっていました。また、マスターページ以外に実装すれば「実験室」のサンプルと同じように動くことを確認しました。 -
  • 「マスターページ以外に実装」というのはブログのコードをコピペしてそれのみで動かしたということですよね。であれば、問題はそこからマスターページへ実装する際にに起こっていると考えるのが妥当ですよね。ちょっと試してみます。 -
  • 試してみました。問題ないはずです。詳しくは回答に書きましたので見てください。 -

細かいところまで見たわけではなく、ざっと見て気がついた点のみですが・・・

GirdView を Content の中に配置した場合、GridView3 という ID はクライアント側の html コードでは変わってしまいます。なので $('#GridView3') とか srcData: "GridView3", ではスクリプトが目的の要素を見つけられません。

参考にした 2 つめのサイトのコードをよく見てください。

GridView1 ではなくて <%=GridView1.ClientID%> になっているのはそれに対応するためです。

編集 履歴 (1)
ウォッチ

この質問への回答やコメントをメールでお知らせします。