none
gridViewのページングについて RRS feed

  • 質問

  • なのですが、スマートタグからデータベースを接続してバインドさせるとタグの中にページの設定が出来るようになっていますが、aspx.csにてデータベースに接続、クエリを行った時、gridView1.DataSource = command.execudeReader();

    gridVIew1.DataBind();でデータは表示する事は出来るのですが、ページの設定をしようとプロパティでAllowPageingをtrueにするとエラーになってしまいます。データソースはpagingをサポートしていません。というメッセージになります。このようにコードでデータベースからgridViewで表示させた場合ページングを簡単にする方法はありますか??

    2007年3月23日 7:28

すべての返信

  • 上記のようにDataReaderを使う場合は自分でページングに対応するプログラムを記述するしかないです。
    SqlDataSourceやObjectDataSourceを利用すれば、それらのクラスがページングをサポートしてくれます。

    まぁ、要件によってどちらを使うか選択することになるでしょう。

    2007年3月23日 8:02
  • アドバイスありがとうございます。例えば、ユーザーがデータを検索したい場合、クエリの中に入力情報をlike文付け加えなくてはいけないと思うので、どうしてもスマートタグからデータを取得できないと思うんですが、となるとdataReader()を使わざるを得ないと考えます。そうなると、検索したデータが限定されたとはいえ、まだ膨大なデータがあるとするとページングをしないといけない場合、言われたように手作業でページングを作らなくてはいけないのでしょうか。また、どのように作成していくのでしょうか。
    2007年3月23日 8:17
  •  KentaroM さんからの引用

    例えば、ユーザーがデータを検索したい場合、クエリの中に入力情報をlike文付け加えなくてはいけないと思うので、どうしてもスマートタグからデータを取得できないと思うんですが、となるとdataReader()を使わざるを得ないと考えます。

    そんなことはないですよ。SqlDataSourceのSelectCommandプロパティにSQL文をセットして、GridViewのDataBindメソッドを実行してあげればよいです。
     KentaroM さんからの引用

    そうなると、検索したデータが限定されたとはいえ、まだ膨大なデータがあるとするとページングをしないといけない場合、言われたように手作業でページングを作らなくてはいけないのでしょうか。また、どのように作成していくのでしょうか。

    SqlDateReaderを使用した場合のページングは、GridViewのAllowPagingをtrueにしておいて、GridViewのPageIndexChangingイベントで処理をしてあげればよいです。
    2007年3月23日 8:34
    モデレータ
  • アドバイスいただいて、いろいろリファレンスとかみているんですが、もう一度おさらいしますと、ページングを設定したいのですが、サポートされていません例外になってしまいます。gridViewのスマートタグからデータをバインドさせると問題なくページングのallowPagingをtrueにして出来ます。SqlConnection conn = new SqlConnection();

    conn.ConnectionString = connection;

    conn.Open();

    SqlCommand command = new SqlCommand();

    command.Connection = conn;

    command.CommandText = "Select * from Login";

    gridView1.DataSource = command.ExecuteReader();

    gridView1.DataBind();

    conn.close();

    の様にして、データを取得します。そしてデザインビューからgridView1のプロパティでallowpagingをtrueにしてデバックするとエラーになります。目標は、ユーザーがさらにtextboxにキーワードを入れ絞込み検索をしたいので、クエリ文に%を足そうと考えています。アドバイスをいただいてSqlDataSourceのSelectCommandにクエリをセットしてバインドさせるという事ですが、これはC#のソースコードでやるのだと思われますが、具体的にどの様にすればいいでしょうか。(htmlコード内ではないですよね。)また、SqlDateReaderを使用した場合のページングは、GridViewのAllowPagingをtrueにしておいて、GridViewのPageIndexChangingイベントで処理をしてあげればよいです。という事ですが、これも具体的にイベントを生成して、e. とやってみると確かpageIndex(int型)等がインテリセンスでありましたがこれもどのようにすればいいのでしょうか?

    2007年3月25日 6:14
  •  KentaroM さんからの引用

    また、SqlDateReaderを使用した場合のページングは、GridViewのAllowPagingをtrueにしておいて、GridViewのPageIndexChangingイベントで処理をしてあげればよいです。という事ですが、

    大変申し訳ないです。SqlDataReaderはページングをサポートしていませんでした。私の手持ちのテストコードの中に、GridViewのページングをSqlDataReaderで実現している例があったものですから、うっかり動くものと勘違いしてしまいました。どうやら動かないことを試したコードだったようです。(^^;

    こちらでも話題にしていました。

    DataGridのページ移動
    http://forums.microsoft.com/msdn-ja/ShowPost.aspx?PostID=463085&SiteID=7

    ごめんなさい。m(_ _)m

     KentaroM さんからの引用

    アドバイスをいただいてSqlDataSourceのSelectCommandにクエリをセットしてバインドさせるという事ですが、これはC#のソースコードでやるのだと思われますが、具体的にどの様にすればいいでしょうか。

    こちらを参考にしてみて下さい。

    検索機能
    http://forums.microsoft.com/msdn-ja/ShowPost.aspx?PostID=579236&SiteID=7

    なお、追加で、下にパラメタライズドクエリとストアドプロシージャを利用する場合のサンプルを載せます。

      protected void Button3_Click(object sender, EventArgs e)
      {

            SqlDataSource1.SelectCommandType = SqlDataSourceCommandType.Text;

            SqlDataSource1.SelectCommand = "select testid, test2id from test where testid = @id";

            SqlDataSource1.SelectParameters.Clear();

            SqlDataSource1.SelectParameters.Add("id", TypeCode.Int32, TextBox1.Text);

            GridView1.DataBind();

        }


        protected void Button4_Click(object sender, EventArgs e)

        {

            SqlDataSource1.SelectCommandType = SqlDataSourceCommandType.StoredProcedure;

            SqlDataSource1.SelectCommand = "test_selectid";

            SqlDataSource1.SelectParameters.Clear();

            SqlDataSource1.SelectParameters.Add("id", TypeCode.Int32, TextBox1.Text);

            GridView1.DataBind();

        }

    なお、like句を使う場合には、パラメータ化しても特殊文字がエスケープされませんから、次のように事前にエスケープしておいてから、%などをくっつける必要があります。

     s = s.Replace("[", "[[]");
     s = s.Replace("%", "[%]");
     s = s.Replace("_", "[_]");

    (参考)
    SQL インジェクション
    http://www.microsoft.com/japan/msdn/security/guidance/secmod87.mspx#EBEAC

    2007年3月25日 16:39
    モデレータ
  • おかげさまで、SqlDataSourceのselectQueryプロパティからtextboxを選択できそれとパラメータに連結させる事が出来ました。あとはボタンクリックイベントに GridView1.DataSource = sqlDataSource1;

    GridView1.DataBind(); とするとコードは2行で検索するデザインが出来上がりました。ナイスです。後は、当初の目的である、ページングです。gridView1のallowPagingをtrueにして今度はコンパイルできました。しかし、次のページを開こうとするとpageIndexChangingにコードを加えなさいとメッセージがでます。試しにe. とやると確かにクリックしたページのindexが出ますがどう設定していけばいいのでしょうか??

    2007年3月26日 9:51
  • GridViewのDataSourceを利用する場合、ページング等の機能は利用できなくなります。
    GridViewのDataSourceIDにSqlDataSourceが設定されている必要があったはず。

    まずデザイン画面でGridViewにSqlDataSourceをバインドしてしまうというのが普通の使い方ですね。
    検索される条件等が変わる場合は、SqlDataSourceのSelect文となるSQLをうまく作っておくとか、動的に変更するとかいった形をとります。

     

    2007年3月26日 10:53
  • その後、表に取ってきたデータの一部を計算して表示する事になり、結局dataReaderを使ってgridviewにバインドする事になっています。(そのうち集計するデータだけ、while(reader.Read()){ dataItem.Revenue = reader["rev"];で取り、計算します。)そうなるとまた問題になってくるのがソートです。htmlタグのgridviewのdataSourceIDにsqlDataSourceなどがバインドされていればプロパティのallowSortingをtrueにして問題ないのですが、コードからgridView1.DataSource = reader;

    gridView1.DataBind(); の様にバインドした場合ソートするとエラーになります。gridVIew1の属性に何か追加するのか一工夫必要な様です。

    2007年3月29日 0:28
  • ソートもページングと同じでDataSource使ってないとサポートされません。
    独自に実装する必要があります。
    2007年3月29日 2:28
  • DataReaderではなくて、DataTableをバインドするようにすれば、AllowPagingとAllowSortingをtrueにして、ページングとソートを実現することが可能です。この場合、どっとねっとふぁんさんが言われているように、GridViewのPageIndexChangingイベントとSortingイベントを独自に処理して、ページングとソートを実現する必要があります。

    2007年3月29日 2:47
    モデレータ
  • アドバイスありがとうございます。結局いろいろ試行錯誤しまして、ソートをIComparerでやり(その方がクエリを呼ばないので早い)ました。ページングはPageIndexChangingイベントで GridView1.PageIndex = e.NewPageIndex; で解決しました。ただ、ただ、その後機能を追加するにあたり、動的にデータベースからGridViewにバインドしながら、静的なインデックスをつけようと思い、いろいろ試しGridVIewのDataRowBoundイベントで、

    if(e.Row.RowType == DataControlRowType.DataRow)

    {

       int i;

       i++;

       e.Row.Cells[0].Text = i.ToString();

    }

    で、ソートしてもリスト番号は変わらない様には出来ました。ただ、これだと、ページングをした時にまた、1,2,3,4...となってしまい、理想は例えばpegesizeが10なら、次のページは11から表示したいのです。だとすると、PageIndexを判別していないとどんどん足されていってしまうので、PageIndexChangingのPageIndexをViewStateで記憶させておけばいいと思ったのですが、なんと、ディバックしてみるとページをクリックしても先にDataRowBoundイベントが始まり、indexを認識できないではありませんか!さらにindexを認識出来たとしても、

    if (ViewState["pageIndex"] != null)

    {

         int pIndex = (int)ViewState["pageIndex"];

    }

    .......

    int pSize = GridView1.PageSize;

    int pageNum = pSize * pIndex;

    if (e.Row.RowType == DataControlRowType.DataRow)

    {

         pageNum++;

         e.Row.Cells[0].Text = pageNum.ToString();

    }

    みたいに考えたのですが、rowが生成される度にpSize * pIndexも通過してしまうので、どのみちうまくいきません。なので、今のところsizeを多めにして1++;のようなページングされても1からになっちゃうものでやっています。

    この状況でいい解決法があるでしょうか??

     

    また、dataTableを使うと言われていましたが、その方法も軽く教えていただけたらうれしいです。

    2007年4月5日 3:27
  •  KentaroM さんからの引用

    また、dataTableを使うと言われていましたが、その方法も軽く教えていただけたらうれしいです。


    ここを参考にしてみて下さい。

     

    C# GridView Sorting/Paging w/o a DataSourceControl DataSource
     http://community.strongcoders.com/content/CSGridViewSortingPaging.aspx

    2007年4月5日 6:03
    モデレータ
  • その後、dataViewを使う方法を試しています。以下の感じでやっています。OracleDataAdapter  dAdapter = new OracleDataAdapter(command); DataSet dSet = new DataSet(); dAdapter.Fill(dSet); DataTable dTable = (DataTable)dSet.Tables[0]; DataView dView = new DataView(dTable); GridView1.DataSource = dView; GridView.DataBind(); Session["dVIew"] = dView;でGridViewに表示できました。ページング、ソートしてもインデックスが変わらない方法は、ItemTemplateのtext属性に<%#  Container.DataItemIndex + 1 %>として解決出来ました。それで、DataViewでバインドした場合、例えば、Priceカラムがあるとして、その合計値をFooterに表示したいのですが、下記のようにやったらうまくいきませんでした。

    double listPrice = 0;

    protected void DataBound(object sender, DataBoundEventArgs e)

    {

                string strList = "";  
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                double listPrice = double.Parse(e.Row.Cells[10].Text);
                listPriceTotal += listPrice;
                strList = String.Format("{0:c}", listPriceTotal);
                Label3.Text = strList;

            }
            if (e.Row.RowType == DataControlRowType.Footer)
            {
                e.Row.Cells[10].Text = Label3.Text;
            }
         }

    Label3はHidden的に使用しています。

    具体的に何がうまくいかないかと言うと、ListPrice列の合計をFooterに表示させたいのですが、1ページ目に表示される合計値は全体の合計ではなく、1ページ目だけの合計値になり2ページ目をクリックすると全体の合計になり、1ページ目に戻っても全体の合計値のままになっています。breakpointでどのように合計が加算されているか調べているのですが、dataBoundイベント発生時とpostbackの関係のせいなのか、思うような結果が得られません。

       

    2007年4月8日 12:51
  • GridViewのRowDataBoundイベントを使って下さい。それから、理由があってLabel3を使用しているのであれば良いですが、そうでなければ、普通に変数を使って合計を求めるのが良いと思います。
    2007年4月8日 15:31
    モデレータ
  • ありがとうございます。ちなみにrowdataboundイベントでやっております。dataTable(dataView)を使ってデータを取得した場合、列の計算はこの様にRowDataBound内でやるんでいいのでしょうか??前回dataReaderでデータを取得した場合は、dataItem.Price = (int)reader["price"]; から int totalPrice += dataItem.Price みたいにしたのですが。
    2007年4月9日 8:15
  •  KentaroM さんからの引用
    ちなみにrowdataboundイベントでやっております。

     

    イベントプロシージャの型が、GridViewRowEventArgsではないため、RowDataBoundではないと思ってしまいました。

     

     KentaroM さんからの引用
    dataTable(dataView)を使ってデータを取得した場合、列の計算はこの様にRowDataBound内でやるんでいいのでしょうか??。

     

    ページングしない時はうまくいくようですが、ページングするとダメなようです。変わりにPreRenderイベントで行うと、うまくいきます。C#ですが、以下のような感じでテストしました。

     

        int sumwk = 0;

     

        protected void GridView1_PreRender(object sender, EventArgs e)

        {

            foreach (GridViewRow gvr in GridView1.Rows)

            {

                sumwk += int.Parse(gvr.Cells[0].Text);

            }

     

            this.Label1.Text = sumwk.ToString();

        }

    2007年4月9日 16:09
    モデレータ
  • preRenderイベントで早速試しましたが、rowDataBoundイベントと同じ結果になってしまいます(ページのサイズ分の合計しか表示されない)。試しにこの二つにブレイクポイントを置いてみましたが、たしかにpreRenderイベントが先に発生します。ただ、データベースからデータを取得する前(ウェブページを最初に起動する時)なので、Label1は0と表示され、データ取得後はrowDataBoundイベントが先に起こるので、結果はどちらも一緒になってしまいます。ただ、foreach(GridViewRow gvr in GridView1.Rows)でrowをループする仕方を教わったので、どこか他のイベントで(つまり、gridViewのpageSizeを問わない)使えればいいのですが・・・。
    2007年4月11日 6:06
  • ちょっと私が勘違いしているかもしれないのですが、合計は、表示されているページ内のみの合計を表示するということなのでしょうか? それとも、表示されているページにかかわらず、全てのページを合計した値を表示するということなのでしょうか?

     

    それと確認ですが、PreRenderはGridViewのPreRenderです。すみません、書き忘れました。(以前、どっとねっとふぁんさんにも指定されたんだった。(^^;)

    2007年4月11日 7:55
    モデレータ
  • その後いろいろ試しまして、いい方法がわかりました。ポイントはページングイベントが起こる前にprice列の合計値を出さないといけないので、button_clickイベントで下記の様にしました。

    int i = Convert.ToInt32(dTable.Compute("SUM(Price)", null); // int.Perseではダメだった

    これで一瞬にして合計値を出してくれました。便利なものみつけました。

    その後、dataViewをバインドしてよくなりました。

    2007年4月12日 3:16