none
ListViewのテンプレートを動的に作成するには? RRS feed

  • 質問

  • お世話になります。
    ASP.NETは、基本的なことしかわからない中級者?です。

    今回、動的に作られたSQLを表示する画面があるのですが、ヘッダの見出しもカラム数も変わり、ヘッダが2行になるパターンもあるのでGridViewより簡単そうなListViewを使ってみようと思っています。
    その場合、LayoutTemplateやItemTemplateはコードビハインドでどのように定義すればいいのでしょうか?
    テンプレートの作り方がわかりません。

    大量のデータになることもありえるのでページングをしようと思っていますが、ListViewでなくてもいいので良い方法を教えてください。

    宜しくお願いします。

    #2009.11.23 18:53追記
    ユーザーが好きな項目を1個以上30個以内でチェックしてそれを該当するデータベースのテーブルから引っ張ってきて表形式で表示する、というのが目的です。
    GridViewでいうAutoGenerateColumnsみたいなことを想定していますが、GridViewではヘッダを2行にするのは大変なので。。。
    どうやるのが適しているのかわからないのでListViewにこだわらずに、やり方をご教示ください。
    2009年11月22日 9:01

すべての返信

  • ITemplateを継承したクラスを作成します。以下が参考になると思いますが、ITemplateで検索すれば他にも例が見つかると思います。

    ▼動的にテンプレート列を作成後、DataTableに関連付け
    http://social.msdn.microsoft.com/Forums/ja-JP/csharpgeneralja/thread/bca29235-32c5-4750-a4b7-189c4733c0c3

    ▼Dynamic Template Columns in the ASP.NET 2.0 GridView Control
    http://www.developer.com/net/asp/article.php/10917_3609991_1

    ▼How to define listview templates in code
    http://stackoverflow.com/questions/92689/how-to-define-listview-templates-in-code


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年11月22日 14:03
    モデレータ
  • かなり時間がない状態なので、最悪、すべてLiteral.Textに突っ込んで吐き出そうかと思っていたところでした。
    回答をいただけて感謝です。
    教えていただいたページを見て、なんとなくはわかったのですがもう少しお付き合いください。

    今回ListViewなので
    LayoutTemplate、ItemTemplate、AlternatingItemTemplateを継承したクラスを作成してみました。(頂いたサンプルページの切り貼りですが・・・)

    '--LayoutTemplate
    public class MyLayoutTemplate
      Implements ITemplate

      public sub InstantiateIn(Byval container as System.Web.UI.Control) 
          Dim oTR as New HtmlTableRow
          oTR.ID = "itemPlaceholder"
          container.Controls.Add(oTR)
      End Sub

    '--ItemTemplate
    public class MyItemTemplate
      Implements ITemplate

      public sub InstantiateIn(Byval container as System.Web.UI.Control) 
          Dim lit as New Literal
          AddHandler lit.DataBinding, AddresOf Me.OnDataBinding

         container.Controls.Add(lit)
      End Sub

      public sub OnDataBinding(Byval sender as Object, Byval e as EventArgs)
          Dim lit as Literal = DirectCast(sender, Literal)
          Dim container As ListViewDataItem = DirectCast(lit.NamingContainer, ListViewDataItem)

          lit.Text = DirectCast(container.DataItem, ListViewDataItem )("xxx").ToString 
      End Sub


    OnDataBindingの記述がまんまコピーしてきてListViewに置き換えた感じなのですが、container.DataItemのところでエラーになってしまいます。
    ("xxx")のところなんて絶対違うのでしょうけどどうしたらよいか分かりませんでした。


    また、静的に定義した場合に下記のようになる時、これを動的に記述するにはどのように書けばいいのでしょうか?
    <asp:ListView ID="ListView1" runat="server">
      <LayoutTemplate>
        <table>
           <tr>
              <th rowspan="2">AAA</th>
              <th colspan="2">BBB</th>
           </tr>
           <tr>
              <th>bbb1</th>
              <th>bbb2</th>
           </tr>
           <tr id="itemPlaceholder" runat="server"></tr>
        </table>
      </LayoutTemplate>
      <ItemTemplate>
         <tr>
            <td><%#Eval("COLUMN1")%></td>
            <td><%#Eval("COLUMN2")%></td>
            <td><div><%#Eval("COLUMN3")%></</div><%#Eval("COLUMN4")%></td>
         </tr>
      </ItemTemplate>
    </asp:ListView>


    今後のためにも達成したいので、どうかお力添えのほど宜しくお願いします。

    2009年11月22日 16:34
  • > OnDataBindingの記述がまんまコピーしてきてListViewに置き換えた感じなのですが、
    > container.DataItemのところでエラーになってしまいます。

    何を ListView の DataSource に設定したのかわかりませんが、trapemiya さんが紹介されていた
    最初のページのように DataTable を使用したのであれば、container.DataItem は DataRowView に
    キャストするのだと思いますが。

    lit.Text = DirectCast(container.DataItem, DataRowView)("xxx").ToString

    ただ、他にも問題がありそうで、そこだけ直してもうまくいかないような気がします。

    > また、静的に定義した場合に下記のようになる時、これを動的に記述するにはどのように書けば
    > いいのでしょうか?

    <ItemTemplate> の中の、

    <td><div><%#Eval("COLUMN3")%></</div><%#Eval("COLUMN4")%></td>

    が変ですが、これは

    <td><div><%#Eval("COLUMN3")%></div><div><%#Eval("COLUMN4")%></div></td>

    の間違いと解釈して、以下のような感じで実現できます。VB はうまく書けないので C# で書きましたが
    不明な点があれば質問してください。

    <%@ 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">
        DataTable CreateDataTable()
        {
            DataTable dt = new DataTable();
            DataRow dr;
    
            dt.Columns.Add(new DataColumn("AAA", typeof(String)));
            dt.Columns.Add(new DataColumn("BBB", typeof(String)));
            dt.Columns.Add(new DataColumn("bbb1", typeof(Int32)));
            dt.Columns.Add(new DataColumn("bbb2", typeof(Decimal)));
    
            for (int i = 0; i < 5; i++)
            {
                dr = dt.NewRow();
                dr["AAA"] = String.Format("AAA{0}", i + 1);
                dr["BBB"] = String.Format("BBB{0}", i + 1);
                dr["bbb1"] = (i + 1) * 1000;
                dr["bbb2"] = (i + 1) * 2000;
                dt.Rows.Add(dr);
            }
            return dt;
        }
        
        public class LayoutTemplate : ITemplate
        {
            public void InstantiateIn(Control container)
            {
                HtmlTable table = new HtmlTable();
    
                HtmlTableRow row = new HtmlTableRow();
                HtmlTableCell cell = new HtmlTableCell();
                cell.RowSpan = 2;
                cell.InnerText = "AAA";
                row.Controls.Add(cell);
                cell = new HtmlTableCell();
                cell.ColSpan = 2;
                cell.InnerText = "BBB";
                row.Controls.Add(cell);
                table.Controls.Add(row);
    
                row = new HtmlTableRow();
                cell = new HtmlTableCell();
                cell.InnerText = "bbb1";
                row.Controls.Add(cell);
                cell = new HtmlTableCell();
                cell.InnerText = "bbb2";
                row.Controls.Add(cell);
                table.Controls.Add(row);
    
                row = new HtmlTableRow();
                row.ID = "itemPlaceholder";
                table.Controls.Add(row);
    
                container.Controls.Add(table);
            }
        }
    
        public class ItemTemplate : ITemplate
        {
            public void InstantiateIn(Control container)
            {
                HtmlTableRow row = new HtmlTableRow();
                
                HtmlTableCell cell = new HtmlTableCell();
                cell.DataBinding += new EventHandler(this.DataBinding1);
                row.Controls.Add(cell);
                
                cell = new HtmlTableCell();
                cell.DataBinding += new EventHandler(this.DataBinding2);
                row.Controls.Add(cell);
                
                cell = new HtmlTableCell();
                HtmlGenericControl div = new HtmlGenericControl("div");
                div.DataBinding += new EventHandler(this.DataBinding3);
                cell.Controls.Add(div);
                div = new HtmlGenericControl("div");
                div.DataBinding += new EventHandler(this.DataBinding4);
                cell.Controls.Add(div);
                row.Controls.Add(cell);
                
                container.Controls.Add(row);
            }
    
            public void DataBinding1(object sender, EventArgs e)
            {
                var container = (HtmlTableCell)sender;
                var dataItem = ((ListViewDataItem)container.NamingContainer).DataItem;
                Literal lit = new Literal();
                lit.Text = ((DataRowView)dataItem)["AAA"].ToString();
                container.Controls.Add(lit);
            }
    
            public void DataBinding2(object sender, EventArgs e)
            {
                var container = (HtmlTableCell)sender;
                var dataItem = ((ListViewDataItem)container.NamingContainer).DataItem;
                Literal lit = new Literal();
                lit.Text = ((DataRowView)dataItem)["BBB"].ToString();
                container.Controls.Add(lit);
            }
    
            public void DataBinding3(object sender, EventArgs e)
            {
                var container = (HtmlGenericControl)sender;
                var dataItem = ((ListViewDataItem)container.NamingContainer).DataItem;
                Literal lit = new Literal();
                lit.Text = ((DataRowView)dataItem)["bbb1"].ToString();
                container.Controls.Add(lit);
            }
    
            public void DataBinding4(object sender, EventArgs e)
            {
                var container = (HtmlGenericControl)sender;
                var dataItem = ((ListViewDataItem)container.NamingContainer).DataItem;
                Literal lit = new Literal();
                lit.Text = ((DataRowView)dataItem)["bbb2"].ToString();
                container.Controls.Add(lit);
            }
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                ListView1.LayoutTemplate = new LayoutTemplate();
                ListView1.ItemTemplate = new ItemTemplate();
                ListView1.DataSource = CreateDataTable();
                ListView1.DataBind();
            }
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:ListView ID="ListView1" runat="server">
            </asp:ListView>
        </div>
        </form>
    </body>
    </html>
    
    2009年11月23日 5:39
  • VBに変換して動かせました!ありがとうございます。
    まだ応用できないあたりがダメダメなんですが。。。

            dt.Columns.Add(new DataColumn("AAA", typeof(String)));
            dt.Columns.Add(new DataColumn("BBB", typeof(String)));
            dt.Columns.Add(new DataColumn("bbb1", typeof(Int32)));
            dt.Columns.Add(new DataColumn("bbb2", typeof(Decimal)));

    のところで、条件によってはAAAだけかもしれないし、CCCやDDDも必要になってくるのですが、
    可変にするにはどうしたらいいのでしょうか?
    最大数分定義しておかなければいけないのでしょうか?

    2009年11月23日 6:45
  • > 条件によってはAAAだけかもしれないし、CCCやDDDも必要になってくるのですが、
    > 可変にするにはどうしたらいいのでしょうか?

    具体的に、「可変」というのはどういうことですか?

    もし「動的に作られたSQLを表示する画面があるのですが、ヘッダの見出しもカラム数も変わ
    り、ヘッダが2行になるパターン」に対応したいのであれば、データソースの中身だけ変更し
    てもダメです。

    「ヘッダが2行」を諦めれば、GridView で何とかなりそうな気がしますが。

    2009年11月23日 7:37
  • > 条件によってはAAAだけかもしれないし、CCCやDDDも必要になってくるのですが、
    > 可変にするにはどうしたらいいのでしょうか?

    具体的に、「可変」というのはどういうことですか?

    もし「動的に作られたSQLを表示する画面があるのですが、ヘッダの見出しもカラム数も変わ
    り、ヘッダが2行になるパターン」に対応したいのであれば、データソースの中身だけ変更し
    てもダメです。

    「ヘッダが2行」を諦めれば、GridView で何とかなりそうな気がしますが。

    質問の仕方が良くなかったですね。すみません。
    可変というのは、ユーザーが好きな項目をチェックしてそれを該当するデータベースのテーブルから引っ張ってきて表形式で表示する、です。

    当初に投稿したように、「動的に作られたSQLを表示する画面があるのですが、ヘッダの見出しもカラム数も変わり、ヘッダが2行になるパターン」に対応したいのです。


    ITemplateを継承して・・・というやり方は、GridViewでいうところのAutoGenericColumnsみたいなことではないのでしょうか。
    教えていただいたやり方はどんな時に使うんですか?

    ヘッダが2行ってGridViewだととても面倒なのでListViewでできれば、と思ったのですがTableタグをゴリゴリ書いて吐き出すしかないのかな・・・
    2009年11月23日 8:02
  • > ITemplateを継承して・・・というやり方は、GridViewでいうところのAutoGenericColumnsみたいな
    > ことではないのでしょうか。

    それはないです。

    それを一番最初に書いておいていただければ、お互いの時間の節約になったと思いますけど。

    > 教えていただいたやり方はどんな時に使うんですか?

    「また、静的に定義した場合に下記のようになる時、これを動的に記述するにはどのように書けばいい
    のでしょうか?」に回答したつもりです。

    2009年11月23日 9:43
  • > ITemplateを継承して・・・というやり方は、GridViewでいうところのAutoGenericColumnsみたいな
    > ことではないのでしょうか。

    それはないです。

    それを一番最初に書いておいていただければ、お互いの時間の節約になったと思いますけど。

    > 教えていただいたやり方はどんな時に使うんですか?

    「また、静的に定義した場合に下記のようになる時、これを動的に記述するにはどのように書けばいい
    のでしょうか?」に回答したつもりです。


    なんか、すみませんでした。
    最初の投稿に追記しました。
    実際、「静的に定義した場合に下記のようになる時、これを動的に記述するには」もわからなかったんですけど、
    回答を頂いて、こうやれば行けるんだ、と思い込んでしまいました。

    改めて、ヘッダやアイテムを動的に作成してバインドするには、どうやるのがスマートかお伺いしたいと思います。
    2009年11月23日 10:07