QA@IT

ASP.NETのGridViewのヘッダー行を複数行にし、各種設定を行いたい。

23061 PV

開発環境:ASP.NET(VS2010,C#.NET, .NETFramework4.0 ブラウザはIE限定)

いつもお世話になっております。

客先要望による、今回実施したい処理は下記になります。
 ・行ヘッダーを2行にしたい
 ・一部の列に関しては2行を結合したい
 ・結合していない列は、1行を横書き、もう1行を縦書き表示としたい

色々とサイトを見させて頂きながらヘッダー行は追加できましたが、現状のヘッダーの上に追加されてしまいます。
それでは、追加された後でヘッダーのテキストを変更したり列を結合しようと思ったのですが、どうしていいのかが分かりません。
現時点では、GridViewのPreRenderイベントに下記コードを記載しています。

 //GridViewにヘッダーを1行追加する。
GridViewRow gvrHeader = new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
TableCell cell1 = new TableCell();
cell1.ColumnSpan = gvBumonList.Columns.Count;
cell1.Text = "";
gvrHeader.Cells.Add(cell1);
gvBumonList.Controls[0].Controls.AddAt(1, gvrHeader);
  • GridView を使うとことまで客の指定なんですか? そうでないなら ListView を使ってはいかがですか? それならかなり自由になりますが。たとえば: http://surferonwww.info/BlogEngine/post/2010/08/26/Paging-with-ObjectDataSource.aspx -
  • 質問者さんが先に立てたスレッドがいくつか放置状態になってます。クローズするまで対応いただけないのでしょうか? -
  • おはようございます。
    現時点でGridViewで動いてるため、今のタイミングで他を含めて変更を行うのは難しいかもしれないので、可能ならGridViewで進めたいとは思います。
    ただ、他画面への影響は大きくないので、まずはListViewを確認させてもらいますね。
    -
  • GridView のヘッダを 2 行にする例は、以前の質問者さんのスレッド http://qa.atmarkit.co.jp/q/9210 で紹介していますので見てください。それが目的に適わないなら、具体的にどこが問題か書いてください。 -
  • 依然として以下のスレッドが放置状態です。何かの事情で中止ということならそれでも結構ですから、その旨書いていただければと思います。
    http://qa.atmarkit.co.jp/q/9203 http://qa.atmarkit.co.jp/q/9211 http://qa.atmarkit.co.jp/q/9215
    -
  • 【追伸】ヘッダのみでなくデータ行まで 2 行にしようということですとそれは無理です(絶対不可能とまでは言いませんが)。GridView は諦めて、ListView を使う方向に進むことをお勧めします。 -
  • スレッドの放置は後でまた処理させて頂きます。 -
  • 今回の目的では、ヘッダーのみ2行でデータは1行ごとになります。
    通常のタイトルを表示する列は1行でいいのですが、2種類の表示を1列に表示する列のみ、ヘッダーを2行として表示しようとしています。
    -
  • 今回はあくまでもヘッダーのみなので、データは1行となります。
    -
  • 先のコメントの繰り返しですが・・・ GridView のヘッダを 2 行にする例は、以前の質問者さんのスレッド http://qa.atmarkit.co.jp/q/9210 で紹介していますので見てください。それが目的に適わないなら、具体的にどこが問題か書いてください。 -
  • 参考にさせて頂いて取り急ぎ、RowCreatedにヘッダー追加部だけを記載してみました。
    しかし、根本的に間違えているのか、ヘッダーは1行のみ表示されました。
    13列までを2行結合、以後を2行にしたいのですがなりません。

    -
  • 回答欄にRowCreatedでの記載内容を書かせて頂きます。 -
  • 今回の確認時は列数は合計23となります。
    下記コード実施だと、row1の列数が13、row2の列数が10となり、単純に23列が表示される形となりました。
    -
  • 質問者さんのコードでなぜダメなのかは調べてませんが、先に紹介したブログの記事の例をベースに例を解答欄にアップしておきます。 -

回答

要するにやりたいことは、

(1) GridView でヘッダのみを細工し部分的に 2 行にする。データ行はオリジナルどおり 1 行で表示。

(2) ヘッダの最初の列からある列までは 1 行(rowspan="2")とし、表示するのはオリジナルの文字列。

(3) 次の列から最後の列までは 2 行にし、上の行にオリジナルの文字列を ':' でスプリットした最初の文字列を横書きに、下の行に "aaa" という文字列を縦書きにする。

ということでいいのですよね?

その理解で、先に紹介したブログの記事、

http://surferonwww.info/BlogEngine/post/2011/04/30/Freezing-GridView-header-and-column.aspx

の例をベースに例を解答欄にアップしておきます。ブログの記事の例は全部で 6 列しかないので、1 ~ 2 列を 1 行(rowspan="2")とし、3 ~ 6 列を 2 行にしています。そのままコピペすれば動くので(Web アプリケーションプロジェクトの場合はコード部分を分けなければなりませんが)試してみてください。

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

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

<script runat="server">
    DataTable CreateDataTable()
    {
        DataTable dt = new DataTable();
        DataRow dr;

        dt.Columns.Add(new DataColumn("Code", typeof(Int32)));
        dt.Columns.Add(new DataColumn("Name", 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("Remarks", typeof(string)));

        for (int i = 0; i < 10; i++)
        {
            dr = dt.NewRow();
            dr["Code"] = i;
            dr["Name"] = "Item " + i.ToString();
            dr["Price"] = 123000 * (i + 1);
            dr["Qty"] = i + 1;
            dr["Amount"] = 123000 * (i + 1) * (i + 1);
            dr["Remarks"] = "Remarks " + i.ToString();
            dt.Rows.Add(dr);
        }
        return dt;
    }

    void Page_Load(Object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            GridView1.DataSource = CreateDataTable();
            GridView1.DataBind();
        }
    }

    protected void GridView1_RowCreated(object sender, 
        GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.Header)
        {

            List<TableCell> cells = new List<TableCell>();
            foreach (TableCell cell in e.Row.Cells)
            {
                cells.Add(cell);
            }

            // この index 以降 2 行にする 
            int cellIndex = 2;

            GridViewRow row1 = new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);           

            for (int i = 0; i < cells.Count; i++ )
            {
                if (i < cellIndex)
                {
                    cells[i].RowSpan = 2;
                }
                else
                {
                    cells[i].Text = cells[i].Text.Split(':')[0];
                }
                row1.Cells.Add(cells[i]);
            }

            GridViewRow row2 = new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);

            for (int i = cellIndex; i < cells.Count; i++)
            {
                TableHeaderCell headerCell = new TableHeaderCell();
                headerCell.Controls.Add(new LiteralControl("aaa"));

                // 縦書きに設定(Qurks モードでないと表示が崩れるので注意)
                headerCell.Style["writing-mode"] = "tb-rl";
                row2.Cells.Add(headerCell);
            }

            GridView1.Controls[0].Controls.Clear();
            GridView1.Controls[0].Controls.Add(row1);
            GridView1.Controls[0].Controls.Add(row2);
        }
    }  
</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" />

</head>
<body>
    <form id="form1" runat="server">

        <asp:GridView ID="GridView1" 
            runat="server" 
            AutoGenerateColumns="False"             
            OnRowCreated="GridView1_RowCreated">
            <Columns>
                <asp:BoundField DataField="Code" HeaderText="コード" >
                </asp:BoundField>
                <asp:BoundField DataField="Name" HeaderText="商品名" >
                </asp:BoundField>
                <asp:BoundField DataField="Price" HeaderText="単価:縦書き" >
                </asp:BoundField>
                <asp:BoundField DataField="Qty" HeaderText="数量:縦書き" >
                </asp:BoundField>
                <asp:BoundField DataField="Amount" HeaderText="合価:縦書き" >
                </asp:BoundField>
                <asp:BoundField DataField="Remarks" HeaderText="備考:縦書き" >
                </asp:BoundField>
            </Columns>
        </asp:GridView>

        <%--ポストバックしても表示が崩れないことの確認用のボタン--%>
        <asp:Button ID="Button1" runat="server" Text="PostBack" />
  </form>
</body>
</html>

編集 履歴 (1)
  • これで、OKだと思います。
    ので、UP評価です。
    -
  • ご回答ありがとうございました。
    上記例を引用し、組み込みましたところヘッダーは2行となり、イメージ的にはほぼOKでした。
    -
  • ほぼと書きましたが、なぜか2行にしているヘッダーの1列だけが書式の縦書きが設定されないのと、この画面において2行にまとめている列の内、1列だけ非表示にする処理を実施したらその唯一横書きとなってしまう列が同時に消えてしまいます。
    ※消えるのは2行目の列だけで1行目の列は消えません。
    -
  • 後、もう1点ございまして、GridViewのページャーを上下に出力しているのですが、上のページャーだけが表示されなくなりました。 -
  • 解決策を出せと言ってますか? それは無理です。あなたが何をしたのかさっぱり分かりませんから。コードの持つ意味、結果としての html ソースをよく考えてみてください。分からなければ、ご自分の会社の上司、先輩と相談された方が早いと思います。何故それをしないのですか? -
  • そもそも、このような裏技的なことしてまで GridView を細工するのは、ListView という手段がある以上、間違っていると言っても過言ではないです。最初のコメントで言ったように ListView を使いましょう。最初の質問から 2 日経っていますが、それだけ時間があれば ListView を勉強する時間を含めて解決していると思います。 -

下記で実施たいことの上二つはできませんか?

HTML-------------------------------
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="SqlDataSource1" EmptyDataText="表示するデータ レコードがありません。" OnPreRender="GridView1_PreRender">
            <Columns>
                <asp:BoundField DataField="id" HeaderText="id" SortExpression="id" />
                <asp:BoundField DataField="num" HeaderText="num" ReadOnly="True" SortExpression="num" />
                <asp:BoundField DataField="item" HeaderText="item" SortExpression="item" />
                <asp:BoundField DataField="qty" HeaderText="qty" SortExpression="qty" />
                <asp:BoundField DataField="unit" HeaderText="unit" SortExpression="unit" />
            </Columns>
        </asp:GridView>
        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:griddemo_csConnectionString1 %>" ProviderName="<%$ ConnectionStrings:griddemo_csConnectionString1.ProviderName %>" SelectCommand="SELECT [id], [num], [item], [qty], [unit] FROM [invlines]"></asp:SqlDataSource>
    </div>
    </form>
</body>

C#-------------------------------
    protected void GridView1_PreRender(object sender, EventArgs e)
        {
            GridView gv = (GridView)sender;

            //GridViewにヘッダーを1行追加する。
            GridViewRow gvrHeader = new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);

            TableCell cell1 = new TableCell();
            TableCell cell2 = new TableCell();
            //TableCell cell3 = new TableCell();
            TableCell cell4 = new TableCell();
            TableCell cell5 = new TableCell();

            cell1.Text = "Cell1";
            cell2.Text = "Cell2";
            cell2.ColumnSpan = 2;
            //cell3.Text = "Cell3";   //cell2をColumnSpan = 2 にしたからとりあえずいらない;
            cell4.Text = "Cell4";
            cell5.Text = "Cell5";

            gvrHeader.Cells.Add(cell1);
            gvrHeader.Cells.Add(cell2);
            //gvrHeader.Cells.Add(cell3);   //cell2をColumnSpan = 2 にしたからとりあえずいらない;
            gvrHeader.Cells.Add(cell4);
            gvrHeader.Cells.Add(cell5);

            gv.Controls[0].Controls.AddAt(1, gvrHeader);
        }
編集 履歴 (0)
protected void GridView_RowCreated(object sender, GridViewRowEventArgs e)
{
    //ヘッダー行の場合
    if (e.Row.RowType == DataControlRowType.Header)
    {
        ////動的作成列のヘッダーの文字を縦書きに設定する。
        //Style myStyle = new Style();
        //myStyle.CssClass = "Tategaki2";

        System.Collections.Generic.List<TableCell> cells = 
       new System.Collections.Generic.List<TableCell>();
        foreach (TableCell cell in e.Row.Cells)
        {
            cells.Add(cell);
        }

        int iCellCnt = cells.Count;     //列数

        //ヘッダー追加用行
        GridViewRow row1 = 
     new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
        GridViewRow row2 = 
     new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);

        //現状のヘッダと同じヘッダ文字列を設定する。
        for (int i = 0; i < iCellCnt; i++)
        {
            if (i < 13)
            {
                cells[i].Text = e.Row.Cells[i].Text;
            }
            else
            {
                string[] sHeader = e.Row.Cells[i].Text.Split(':');
                cells[i].Text = sHeader[0];
            }
        }

        //13列まではセル結合(2行を1列)とする。
        for (int i = 0; i < 13; i++)
        {
            cells[i].RowSpan = 2;
        }

        //1行目に全セルを設定する。
        for (int i = 0; i < iCellCnt; i++)
        {
            row1.Cells.Add(cells[i]);
        }

        //2行目は結合していない列のみを追加する。
        for (int i = 13; i < iCellCnt; i++)
        {
            row2.Cells.Add(cells[i]);
        }

        for (int i = 0; i < row2.Cells.Count; i++)
        {
            row2.Cells[i].Text = "aaa";
        }

        row2.CssClass = "Tategaki2";

        //GridViewのヘッダーを設定する。
        GridView.Controls[0].Controls.Clear();
        GridView.Controls[0].Controls.Add(row1);
        GridView.Controls[0].Controls.Add(row2);
    }



編集 履歴 (0)
  • すみません、一気に物事を進ませすぎです。
    一つ一つ検証していきましょう。
    -
  • ご教示ありがとうございます。
    すごい自分自身が理解できてないまま焦っていたので、どうしても一気になんとかしようとしてしまっていました。
    -

DataControlRowState.Normal を DataControlRowState.Alternate に変えれば下に追加されませんか?

編集 履歴 (0)
  • こんにちは。
    変更してみましたけど、状況は変更されませんでした。
    -
ウォッチ

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