none
Integer型配列変数の宣言位置による挙動の違いについて RRS feed

  • 質問

  • 10年ぶりにプログラミングをしています。ASP.NET+VBでWEBフォームを作成しております。
    GridViewのFooterRowに合計を表示するため、以下のようなコードを作成しました。

    Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
        Dim i As Integer
        Dim total(3) As Integer
        Dim cname() As String = New String(3) {"hoge0", "hoge1", "hoge2", "hoge3"}
        Select Case e.Row.RowType
            Case DataControlRowType.DataRow
                For i = 0 To 3
                    total(i) += CInt(DataBinder.Eval(e.Row.DataItem, cname(i)))
                Next
            Case DataControlRowType.Footer
                For i = 0 To 3
                    e.Row.Cells(i + 2).Text = total(i).ToString("#,##0")
                Next
        End Select
    End Sub

    上記コードの結果、FooterRowの合計値は全て「0」で返ってきてしまいます。
    一方で、Dim total(3) as Integer の宣言をページ冒頭ですれば、意図した通りに合計が計算されます。

    この挙動の違いについて、理由がわからず、とまどっている状況です。
    数値型の配列は、Protected Sub内で宣言してはダメなのでしょうか?

    2020年6月16日 1:48

回答

  • すでに解決済みとなっていますが、せかっくレスを書いたのでアップしておきます。

    GridView1_RowDataBound メソッドの中の Dim total(3) As Integer の行にブレークポイントを設定しデバッグ実行してみてください。

    RowDataBound イベントはヘッダ、フッタを含めた行の数だけ発生しますが、そのたび GridView1_RowDataBound メソッドが呼び出され Dim total(3) As Integer で total の各要素はゼロに初期化されるのが分かると思います。

    そして、最後にフッタ行で RowDataBound イベントが発生し GridView1_RowDataBound メソッドが実行されると再び Dim total(3) As Integer で total の各要素はゼロに初期化されます。

    e.Row.Cells(i + 2).Text = total(i).ToString("#,##0") でフッタに値を書き出していますが、total 全要素はゼロなので、

    > 上記コードの結果、FooterRowの合計値は全て「0」で返ってきてしまいます。

    ということになります。

    質問者さんが気付かれた通り、

    > Dim total(3) as Integer の宣言をページ冒頭ですれば、意図した通りに合計が計算されます。

    とすれば、前回の RowDataBound イベントでの total の各要素の値は保持されますので、そうするのが正解です。

    その他、値の取得方法など見直した方がよさそうなところがあります。以下の記事のようにしてはいかがでしょう?

    GridView, ListView に合計表示
    http://surferonwww.info/BlogEngine/post/2010/11/07/Show-sum-in-GridView-or-ListView.aspx

    2020年6月16日 4:47
  • ご提示いただいたプログラムだけを拝見して言えることは・・・、
    このSubの中でtotal()にセットされた値は、Subから一度出る際に失われます。

    total()に値をセットする動作と、e.RowCells().Textに値をセットする動作は、このSubの1回の実行で両方行うのではなく、このSubの別の回の実行になるんだと推察します。そうであれば、e.RowCells().Textに値をセットする際のtotal()の値は、ご提示いただいたプログラムの場合は初期値しか入っておらず、ゼロになってしかるべきです。



    2020年6月16日 3:56

すべての返信

  • ご提示いただいたプログラムだけを拝見して言えることは・・・、
    このSubの中でtotal()にセットされた値は、Subから一度出る際に失われます。

    total()に値をセットする動作と、e.RowCells().Textに値をセットする動作は、このSubの1回の実行で両方行うのではなく、このSubの別の回の実行になるんだと推察します。そうであれば、e.RowCells().Textに値をセットする際のtotal()の値は、ご提示いただいたプログラムの場合は初期値しか入っておらず、ゼロになってしかるべきです。



    2020年6月16日 3:56
  • 外池様

    ご見解をいただき、ありがとうございました。
    配列だからダメということではなく、変数の有効範囲の問題ということですね。

    ご見解を参考に、配列ではなく、愚直にtotal0,total1,total2,total3という4つの変数を作成して試しました。
    結果、同様に、Protected Sub内で宣言したら全て0に、ページ冒頭で宣言したら合計値が表示されました。

    原因が理解できました。大変ありがとうございました。

    2020年6月16日 4:37
  • すでに解決済みとなっていますが、せかっくレスを書いたのでアップしておきます。

    GridView1_RowDataBound メソッドの中の Dim total(3) As Integer の行にブレークポイントを設定しデバッグ実行してみてください。

    RowDataBound イベントはヘッダ、フッタを含めた行の数だけ発生しますが、そのたび GridView1_RowDataBound メソッドが呼び出され Dim total(3) As Integer で total の各要素はゼロに初期化されるのが分かると思います。

    そして、最後にフッタ行で RowDataBound イベントが発生し GridView1_RowDataBound メソッドが実行されると再び Dim total(3) As Integer で total の各要素はゼロに初期化されます。

    e.Row.Cells(i + 2).Text = total(i).ToString("#,##0") でフッタに値を書き出していますが、total 全要素はゼロなので、

    > 上記コードの結果、FooterRowの合計値は全て「0」で返ってきてしまいます。

    ということになります。

    質問者さんが気付かれた通り、

    > Dim total(3) as Integer の宣言をページ冒頭ですれば、意図した通りに合計が計算されます。

    とすれば、前回の RowDataBound イベントでの total の各要素の値は保持されますので、そうするのが正解です。

    その他、値の取得方法など見直した方がよさそうなところがあります。以下の記事のようにしてはいかがでしょう?

    GridView, ListView に合計表示
    http://surferonwww.info/BlogEngine/post/2010/11/07/Show-sum-in-GridView-or-ListView.aspx

    2020年6月16日 4:47
  • SuferOnWww様

    詳細なアドバイス、ありがとうございます。
    GridView_RowDataBoundイベントは、行の数だけ発生する
    → イベント内で変数宣言しても、行が次に進めば変数初期化される。

    私が混乱していた内容が、全て紐解けました。

    各行の値取得方法につきましても、参考にさせていただきました。
    DataBinderなど通さなくても、シンプルにe.Row.DataItemで取得できること、確認できました。

    2020年6月16日 5:45