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

Category: fx aspnet_ja

Question

SoushokukeiOyaji on Tue, 16 Jun 2020 01:48:30


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内で宣言してはダメなのでしょうか?

Replies

外池 on Tue, 16 Jun 2020 03:56:46


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

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



SoushokukeiOyaji on Tue, 16 Jun 2020 04:37:51


外池様

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

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

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

SurferOnWww on Tue, 16 Jun 2020 04:47:35


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

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

SoushokukeiOyaji on Tue, 16 Jun 2020 05:45:55


SuferOnWww様

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

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

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