WebSurfer's Home

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

GridView の Pager に総レコード数を表示

by WebSurfer 2014年12月6日 18:26

以下の画像のように、ページングが有効になっている GridView の Pager 内に「総レコード数」を表示するにはどうしたらいいかということを書きます。

Pager に総レコード数を表示

ListView と DataPager を利用する場合は、先の記事 ListView でページ指定 のサンプルコードのように Container.TotalRowCount で総レコード数が取得できます。(注:Container は DataPager オブジェクトを参照しています)

しかしながら、GirdView を利用した場合、ページング機能は GirdView に統合されているものを利用することになり、それから「総レコード数」を取得するプロパティなどはありません。

GridView は、データーソースコントロール(SqlDataSource または ObjectDataSource)と組み合わせて使うケースがほとんどだと思いますが、その場合はデーターソースコントロールの Selected イベントのハンドラを使って「総レコード数」を取得するのが簡単そうです。

例えば、データーソースコントロールに SqlDataSource を使う場合、その Selected イベントのハンドラの引数 SqlDataSourceStatusEventArgs クラスAffectedRows プロパティ から総レコード数を取得できます。

取得した「総レコード数」をページャーの中に表示するには、GridView.RowDataBound イベント のハンドラでページャーの行を探して、その中に追加します。

ページャーそのものはデフォルトで(何も設定しなくても) 1 2 3 4 5 6 7 8 9 10 ... というようなクリックするとその番号のページに飛べるハイパーリンクが生成されますが、PagerSettings クラス を使うともう少し細かな設定ができます。

上の画像のページャーは、PagerSettings クラスの Mode プロパティを NumericFirstLast に、PageButtonCount プロパティを 5 に設定した場合のものです。

SqlDataSource と GridView を使った場合のサンプル(上の画像のページを表示したもの)を以下にアップしておきます。

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

  int GridView3TotalCount = 0;
    
  protected void SqlDataSource1_Selected(
        object sender, SqlDataSourceStatusEventArgs e)
  {
      GridView3TotalCount = e.AffectedRows;
  }

  protected void GridView3_RowDataBound(
        object sender, GridViewRowEventArgs e)
  {
    if (e.Row.RowType == DataControlRowType.Pager)
    {
      Label label = new Label();
      label.Text = "総レコード数: " + 
            GridView3TotalCount.ToString();
      e.Row.Cells[0].Controls.AddAt(0, label);
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>GridView Total Records</title>
</head>
<body>
  <form id="form1" runat="server">
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
      ConnectionString="<%$ ConnectionStrings:Northwind %>" 
      SelectCommand="SELECT * FROM [Orders]" 
      OnSelected="SqlDataSource1_Selected">
    </asp:SqlDataSource>

    総レコード数: <%=GridView3TotalCount%>
    <asp:GridView ID="GridView3" runat="server" 
      AllowPaging="True" 
      AutoGenerateColumns="False" 
      DataKeyNames="OrderID" 
      DataSourceID="SqlDataSource1" 
      OnRowDataBound="GridView3_RowDataBound">
      <PagerSettings 
        Mode="NumericFirstLast" 
        PageButtonCount="5">
      </PagerSettings>
      <Columns>
        <asp:BoundField DataField="OrderID" 
          HeaderText="OrderID" 
          InsertVisible="False" 
          ReadOnly="True" 
          SortExpression="OrderID" />
        <asp:BoundField DataField="CustomerID" 
          HeaderText="CustomerID" 
          SortExpression="CustomerID" />
        <asp:BoundField DataField="OrderDate" 
          HeaderText="OrderDate" 
          SortExpression="OrderDate" 
          DataFormatString="{0:yyyy/MM/dd}" />
        <asp:BoundField DataField="Freight" 
          HeaderText="Freight" 
          SortExpression="Freight" 
          DataFormatString="${0:N2}" />
        <asp:BoundField DataField="ShipCountry" 
          HeaderText="ShipCountry" 
          SortExpression="ShipCountry" />
      </Columns>
    </asp:GridView>
  </form>
</body>
</html>

データーソースコントロールに ObjectDataSource を使う場合も、ObjectDataSource.Selected イベントのハンドラ で「総レコード数」を取得できます。

ObjectDataSource を使う場合、ページを切り替えるたびに全レコードを DB から再度取得するという無駄なことを避けるため、普通は、先の記事 ObjectDataSource でページング に書いてあるように、必要なレコードのみ DB から取得するクラス/メソッドを実装して、それらを ObjectDataSource で定義されているプロパティに設定することになると思います。

上に紹介した記事のサンプルコードでは、GetDataByIndex と GetNumberOfMessages の 2 つのメソッドが ObjectDataSource に設定されていますが、その両方が呼ばれ、それぞれで Selected イベントが発生します(2 回 Selected イベントが発生します)。

その際、イベントハンドラの引数 ObjectDataSourceStatusEventArgs の ReturnValue プロパティ でそれぞれのメソッドが返すオブジェクトを取得できます。

したがって、e.ReturnValue が Int32 型にキャストできれば GetNumberOfMessages が返したもの、即ち全レコード数ということになります。なので、イベントハンドラのコードを以下のようにすれば「総レコード数」を取得できます。

protected void ObjectDataSource1_Selected(object sender, 
                        ObjectDataSourceStatusEventArgs e)
{
  if (e.ReturnValue is Int32)
  {
    GridView3TotalCount = (Int32)e.ReturnValue;
  }
}

「総レコード数」さえ取得できれば、あとは GridView と Pager の実装を SqlDataSource を使った場合と同様にして Pager に表示できます。

Tags: ,

Paging

MySQL と SqlDataSource の問題

by WebSurfer 2014年11月24日 17:10

Visual Studio 2010 Professional 上で MySQL と SqlDataSource を使って ASP.NET Web Forms アプリを作った時に遭遇した問題を書きます。

クエリのテスト結果

なお、使ったのは 3 年以上前にインストールした MySQL Community Server 5.5.11 と Connector/Net 6.3.6 ですので、最新版では様子が違うかもしれません。ご注意ください。

問題は、簡単に書くと、Visual Studio の「データソースの構成」ウィザードを使ってクエリを自動生成すると、識別子がスクエアブラケット( [ ] )で囲まれますが、それが MySQL では使えないので、上の画面のようなエラーが出るということです。

具体的な再現手順を書くと、(1) Visual Studio のデザイン画面で SqlDataSource の > 印をクリック、(2) 表示される「SqlDataSource タスク」メニューの中の[データ ソースの構成...]をクリック、(3) ウィザードの「Select ステートメントの構成」画面で[テーブルまたはビューから列を指定します(T)]を選択、(4) 次の画面「クエリのテスト」に進んでテストを実行、(5) 上の画面のようなエラーが出る・・・ということです。

上のエラーメッセージで、テーブル名 employees がスクエアブラケット( [ ] )で囲まれているのが分かるでしょうか? ちなみに、ウィザードで生成されたソースは以下のようになります。(注:この例では列に * を選択しています。実際の列を指定すると列名もスクエアブラケットで囲まれます)

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
  ConnectionString="<%$ ConnectionStrings:MySQL %>" 
  ProviderName="<%$ ConnectionStrings:MySQL.ProviderName %>" 
  SelectCommand="SELECT * FROM [employees]">
</asp:SqlDataSource>

もちろんこの状態で実行しても以下のようにサーバーエラーになります。

サーバーエラー

解決策は、生成されたソースのクエリからスクエアブラケットを削除するか、スクエアブラケットに換えてバッククォート( ` )で囲むことです(識別子が予約語と同じ、または特殊文字を含む場合)。

または、上の再現手順の (3) のステップで[カスタム SQL ステートメントまたはストアド プロシージャを指定する(S)]を選んで、自力でクエリを組み立ててもいいです。

ただし、SELECT だけならそれでもいいですが、INSERT, DELETE, UPDATE も必要な場合は少々面倒です。

Visual Studio のデータスース構成ウィザードを使って型付 DataSet + TableAdapter を作った場合は、識別子は正しくバッククォート( ` )で囲まれ上記のような問題はありませんので、それと ObjectDataSource を組み合わせて使う方が良さそうです。

Tags:

MySQL

ModalPopup と Firefox の問題

by WebSurfer 2014年11月6日 16:46

Ajax Control Toolkit の ModalPopup を Firefox で表示した場合、一旦表示して消した ModalPopup が、別ページに遷移する前に一瞬表示されてしまう問題とその対処方法の紹介です。

遷移前に一瞬表示された ModalPopup

上の画像は、[Show ModalPopup]ボタンをクリック ⇒ ModalPopup が表示される ⇒ ModalPopup 上の[Cancel]ボタンクリック ⇒ ModalPopup が非表示になる ⇒[ブログのページへ]のハイパーリンクをクリックした時、遷移先のページからの応答を待っている時のものです。応答を待っている間、本来表示されてはいけない ModalPopup が表示されてしまっています。

この問題は、ブラウザが Firefox の場合で(現時点での最新バージョン 33.0.2 で確認)、かつ、ModalPopup の DropShadow プロパティが true に設定された場合に発生します。

そのメカニズムは以下の通りです。

DropShadow="true" となっていると、ModalPopup の PopupControlID プロパティに設定した Panel の外側が div 要素で囲われ、その style 属性に "display: none;" が追加 / 削除さることによって ModalPopup の非表示 / 表示が切り替えられます。

たとえ Panel の Style プロパティに "display: none;" を設定しておいても、一旦 ModalPopup を表示するとその設定は削除され、その後 ModalPopup を非表示にしても Panel の "display: none;" は復活しません。(その外側の div 要素に動的に追加される "display: none;" によって非表示になる)

Firefox の場合、ハイパーリンクがクリックされて、遷移先のページを要求に行くとき、Panel の外側の div 要素そのものがなくなるか、その div 要素に設定されている "display: none;" の効果がなくなり、要求を出してから応答が帰ってくるまで Panel が表示されてしまうという感じです。(推測です。実際にどうなっているのかは不明)

ハイパーリンクでなくリダイレクトで遷移しても同じで、GET 要求を出してから応答が戻ってくるまで Panel は表示されてしまいます。

なお、この問題は DropShadow="false" になっていると起こりません。なぜなら、その場合は Panel は div 要素で囲われることはなく、Panel に直接 "display: none;" が追加 / 削除され ModalPopup の非表示 / 表示が切り替えられるからです。

対症療法的ですが、ハイパーリンクの onclick イベントで、ModalPopup (Panel) の style 属性に "display:none;" を設定することでこの問題を回避できます。

そのサンプルコードを以下に書いておきます。また、実際に動かして試すことができるよう 実験室 にアップしました。興味のある方は試してみてください。

<%@ Page Language="C#" %>

<%@ Register Assembly="AjaxControlToolkit" 
    Namespace="AjaxControlToolkit" TagPrefix="asp" %>

<!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>ModalPopup と Firefox</title>
  <style type="text/css">       
    .modalBackground {
      background-color: Gray;
      filter: alpha(opacity=70);
      opacity: 0.7;
    }

    .modalPopup {
      height: 100px;
      width: 250px;
      background-color: White;
      border: solid 2px black;
    }
  </style>
  <script type="text/javascript">
  //<![CDATA[
    function setDisplayNone() {
      var ele = document.getElementById('<%=Panel1.ClientID%>');
      ele.setAttribute('style', 'display: none;');
    }
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <asp:ToolkitScriptManager ID="ToolkitScriptManager1" 
    runat="server">
  </asp:ToolkitScriptManager>

  <h1>ModalPopup と Firefox</h1>

  <asp:Button ID="Button1" 
    runat="server" 
    Text="Show ModalPopup"/>    
  <br />
  <asp:HyperLink ID="HyperLink1" 
    runat="server" 
    NavigateUrl="~/Default.aspx">
    ブログのページへ
  </asp:HyperLink>
  <br />
  <asp:HyperLink ID="HyperLink2" 
    runat="server" 
    NavigateUrl="~/Default.aspx"
    onclick="setDisplayNone();">
    ブログのページへ(display:none 設定)
  </asp:HyperLink>

  <asp:ModalPopupExtender ID="ModalPopupExtender1" 
    runat="server"
    TargetControlID="Button1" 
    PopupControlID="Panel1"        
    BackgroundCssClass="modalBackground" 
    DropShadow="True"
    CancelControlID="CancelButton">
  </asp:ModalPopupExtender>

  <asp:Panel ID="Panel1" 
    runat="server"  
    Style="display: none" 
    CssClass="modalPopup">        
    <p style="text-align: center;">ModalPopup</p>
    <p style="text-align: center;">
      <asp:Button ID="CancelButton" 
        runat="server" Text="Cancel" />
    </p>
  </asp:Panel>
  </form>
</body>
</html>

Tags: , ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar