DOBON.NET DOBON.NETプログラミング掲示板過去ログ

datagridviewでの行番号の表示

環境/言語:[WindowsXP、NET Framework(2.0.50727)]
分類:[.NET]

こんにちは、satsukiと申します。
あちこち調べましたが、わかりませんでしたので、どなたかご教示お願いいたします。

datagridviewのdatasourceにdatatableをセットして一覧表示をしています。
datagridviewの右下に現在位置の行番号と行の総数を/で区切って表示したいのですが、表示直後に1行目にカーソルがあたっているにも関わらず、currentrowやselectedrowの値を調べると0になっています。
画面表示直後に「1/500」などというように表示するにはどのようにしたらよいでしょうか?
■No24433に返信(satsukiさんの記事)
> datagridviewのdatasourceにdatatableをセットして一覧表示をしています。
大文字と小文字を区別せずに記述しているということは、
VBをお使いなのでしょうか?

> datagridviewの右下に現在位置の行番号と行の総数を/で区切って表示したいのですが、
行番号を取得したいのであれば、CurrentCellAddress プロパティを
利用してください。CurrentRow を使うよりも効率が良いです。

行の総数は、RowCount プロパティです。


> 表示直後に1行目にカーソルがあたっているにも関わらず、
> currentrowやselectedrowの値を調べると0になっています。
SelectedRow というプロパティは、DataGridView には無かったと思います。
SelectedRows ならばありますけれども。

で。番号は 0 から始まりますから、先頭行にカーソルがあるのなら、
それは「0行目」です。その次の行にいるなら「1行目」ですね。
■No24434に返信(魔界の仮面弁士さんの記事)

魔界の仮面弁士さん、アドバイスありがとうございます。

> 大文字と小文字を区別せずに記述しているということは、
> VBをお使いなのでしょうか?
はい、そうです。説明不足で申し訳ありません。

> 行番号を取得したいのであれば、CurrentCellAddress プロパティを
> 利用してください。CurrentRow を使うよりも効率が良いです。
早速、CurrentCellAddressを使ってみましたら、エラーがでるので、
使い方を調べてみましたら、pointとかいう型として扱うとありました。
Dim value1 As Point = datagridview1.CurrentCellAddress
として、値を確認してみましたら、x=-1 y=-1 となっております。
datagridview1.datasource = datatable1
とするだけで、表示はできているのですが、カーソルを一行目にセットする
記述が別に必要なのでしょうか?

↓のご指摘のとおり「SelectedRow」ではなく「SelectedRows」の書き間違いですが、そのSelectedRowsのcountプロパティの値が0だったのです。
行位置の取得は、datagridview1.SelectedRows.Item(0).Indexとしていましたが、
「indexが範囲を超えています」というエラーがでます。
> SelectedRow というプロパティは、DataGridView には無かったと思います。
> SelectedRows ならばありますけれども。
> で。番号は 0 から始まりますから、先頭行にカーソルがあるのなら、
> それは「0行目」です。その次の行にいるなら「1行目」ですね。

> 行の総数は、RowCount プロパティです。
「datagridview1」でSelectedRows.countプロパティを調べると、1になっていますが、「datagridview1.SelectedRows」でcountプロパティを調べると0なのです。
ちなみにRowCountプロパティは正しい数字がでています。

再度、ご教示お願いいたします。
この場合は「SelectedRows]ではなく「Rows」で良いと思うのですが?

または接続しているDataTable側の行数を使うとか。
■No24440に返信(ヴァンさんの記事)

ヴァンさん、アドバイスありがとうございます。

> この場合は「SelectedRows]ではなく「Rows」で良いと思うのですが?
datagridview1.Rowsのプロパティを見てみたら、countとitemがあったので、
datagridview1.Rows.Item(0).Index
としてみたら、エラーは出なくなりましたが、Item(7)とか、あり得ない値
にしてもエラーはでません。itemについて調べてみましたが、使い方や何を
指すのかがよくわかりませんでした。

> または接続しているDataTable側の行数を使うとか。
datagridviewの中で行を削除したりするのですが、datatable側の行数でも
問題ないでしょうか?
こんばんは。

>Item(7)とか、あり得ない値にしてもエラーはでません。

これの場合、どの部分があり得ない値になるのでしょうか?
8行以上のデータがあればあり得ないということはありません。
■No24438に返信(satsukiさんの記事)
> Dim value1 As Point = datagridview1.CurrentCellAddress
> として、値を確認してみましたら、x=-1 y=-1 となっております。
という事は、現在はアクティブなセルが無い状態ということですね。

行番号の表示は、どのイベントに書いていますか?
(セル位置が変わったときに、情報を更新しなければいけませんから、
DataGridView 上のどこかのイベントに記述しているのでしょうけれども)

> datagridview1.datasource = datatable1
> とするだけで、表示はできているのですが、カーソルを一行目にセットする
> 記述が別に必要なのでしょうか?
アクティブなセル位置をコードで変更することは可能です。また、
コードで指定していない場合は、左上のセルが初期位置となります。
ただし、データが表示される前の段階では、アクティブなセルが
存在しない状態にもなりえます。

> ↓のご指摘のとおり「SelectedRow」ではなく「SelectedRows」の書き間違いですが、そのSelectedRowsのcountプロパティの値が0だったのです。
SelectedRows.Count と Rows.Count と RowCount の使い分けはできていますか?

> 行位置の取得は、datagridview1.SelectedRows.Item(0).Indexとしていましたが、
> 「indexが範囲を超えています」というエラーがでます。
それは当然だと思いますよ。
先ほど、CurrentCellAddress.Y が -1 だったのですから、選択されているセルは
存在しない状態です。という事は、選択された行も無い事になりますので、
SelectedRows コレクションは空の状態(SelectedRows.Count = 0)ですからね。

> 「datagridview1」でSelectedRows.countプロパティを調べると、1になっていますが、「datagridview1.SelectedRows」でcountプロパティを調べると0なのです。
――それは、どういう意味でしょうか?

datagridview1 で SelectedRows.countプロパティが 1 であるが、
datagridview1.SelectedRows で countプロパティは 0 になるというのは、
矛盾しているように思えます。
■No24443に返信(ヴァンさんの記事)

ヴァンさん、お返事ありがとうございます。

> >Item(7)とか、あり得ない値にしてもエラーはでません。
>
> これの場合、どの部分があり得ない値になるのでしょうか?
> 8行以上のデータがあればあり得ないということはありません。

すいません。1行しか表示しないもうひとつのdatagridviewと勘違いしておりました。実際のデータは300件以上ありました。。
■No24444に返信(魔界の仮面弁士さんの記事)

魔界の仮面弁士さん、お返事ありがとうございます。

> という事は、現在はアクティブなセルが無い状態ということですね。
> 行番号の表示は、どのイベントに書いていますか?
> (セル位置が変わったときに、情報を更新しなければいけませんから、
> DataGridView 上のどこかのイベントに記述しているのでしょうけれども)
> アクティブなセル位置をコードで変更することは可能です。また、
> コードで指定していない場合は、左上のセルが初期位置となります。
> ただし、データが表示される前の段階では、アクティブなセルが
> 存在しない状態にもなりえます。
調べてみましたら、フォームオープン時に行番号を取得するコードは、データが表示される前の段階に書かれていました。
これで理解できました。アクティブセルがないので、selectedrows.countやcurrentrow.cells.countが0になるのですね。

> SelectedRows.Count と Rows.Count と RowCount の使い分けはできていますか?
使い分けができておりませんでした。ちなみにSelectedRows.Countの値は0
Rows.Count と RowCountの値は342件です。

> それは当然だと思いますよ。
> 先ほど、CurrentCellAddress.Y が -1 だったのですから、選択されているセルは
> 存在しない状態です。という事は、選択された行も無い事になりますので、
> SelectedRows コレクションは空の状態(SelectedRows.Count = 0)ですからね。
これについても納得しました。値取得のタイミングの問題ですね。

> ――それは、どういう意味でしょうか?
> datagridview1 で SelectedRows.countプロパティが 1 であるが、
> datagridview1.SelectedRows で countプロパティは 0 になるというのは、
> 矛盾しているように思えます。
これについては、私も理解できませんが、クイックウォッチで確認するとそのような値がでました。
解決済み!
# あえて解決済みチェックを外します。

■No24448に返信(satsukiさんの記事)
> これで理解できました。アクティブセルがないので、selectedrows.countやcurrentrow.cells.countが0になるのですね。

そんなハズはありません。焦らず、もう一度よく調査してみてください。
アクティブセルが無い場合には、現在行(CurrentRow)が無いのですから、
> currentrow.cells.countが0になるのですね。
とはならず、NullReferenceException の例外となるはずですよ。

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
 DataGridView1.AllowUserToAddRows = False

 DataGridView1.DataSource = Nothing
 DataGridView1.ColumnCount = 0
 DataGridView1.RowCount = 0

 ' NullReferenceException
 Dim c As Integer = DataGridView1.CurrentRow.Cells.Count

 MsgBox(c)
End Sub


>>SelectedRows.Count と Rows.Count と RowCount の使い分けはできていますか?
> 使い分けができておりませんでした。ちなみにSelectedRows.Countの値は0
> Rows.Count と RowCountの値は342件です。

SelectedRows は、現在選択されている行の集まりです。
複数行選択されている場合、複数の行を返しますし、
選択されている行が無ければ、コレクションは0件となります。

Rows.Count と RowCount は、値の設定ができるかどうかという違いがあります。
取得する時点においては、Rows.Count と RowCount は同義です。
ただし件数の取得だけであれば、RowCount の方がパフォーマンスは上です。


>>> 「datagridview1」でSelectedRows.countプロパティを調べると、1になっていますが、
>>> 「datagridview1.SelectedRows」でcountプロパティを調べると0なのです。
>>datagridview1 で SelectedRows.countプロパティが 1 であるが、
>>datagridview1.SelectedRows で countプロパティは 0 になるというのは、
>>矛盾しているように思えます。
> これについては、私も理解できませんが、クイックウォッチで確認するとそのような値がでました。
私が理解できないのは、0/1 を返すという動作についてではなく、
satsuki さんが説明して下さった内容についてです。

質問文を見る限り、どちらも
  Dim c As Integer = DataGrid1.SelectedRows.Count
といった同じコードを意味する内容に見えたのですが、
それぞれの違いは何なのでしょうか?

一方が Rows の書き間違いであったとか、あるいはそれぞれの行を、
別のイベントで値を取得しているといった話でも無いのだとすると、
クイックウォッチで確認するたびに、結果が 1 と 0 の間で
交互に変化するという事なのでしょうか?
魔界の仮面弁士さん、お返事ありがとうございます。

> そんなハズはありません。焦らず、もう一度よく調査してみてください。
> アクティブセルが無い場合には、現在行(CurrentRow)が無いのですから、
> NullReferenceException の例外となるはずですよ。
↓のコードをコピーしてみましたら、確かにNullReferenceException の例外になりました。
私のコードはDataGridView1.DataSourceにdatatable1が設定してあるので、NullReferenceExceptionにはならないようです。
ただ、datasourceプロパティへの設定後に、行番号の値を取得していますが、
Public Sub Initialize○○○()というプロシージャの中に書かれており、Loadイベントではありません。
また、この中でほかのモジュールをいろいろ呼び出して、最後にdatagridview1を表示する形になっています。

> Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
>  DataGridView1.AllowUserToAddRows = False
>
>  DataGridView1.DataSource = Nothing
>  DataGridView1.ColumnCount = 0
>  DataGridView1.RowCount = 0
>
>  ' NullReferenceException
>  Dim c As Integer = DataGridView1.CurrentRow.Cells.Count
>
>  MsgBox(c)
> End Sub

> SelectedRows は、現在選択されている行の集まりです。
> 複数行選択されている場合、複数の行を返しますし、
> 選択されている行が無ければ、コレクションは0件となります。
それについては、理解できました。

> Rows.Count と RowCount は、値の設定ができるかどうかという違いがあります。
> 取得する時点においては、Rows.Count と RowCount は同義です。
> ただし件数の取得だけであれば、RowCount の方がパフォーマンスは上です。
値の設定ができるかどうかという違いがよくわかりません。


> 私が理解できないのは、0/1 を返すという動作についてではなく、
> satsuki さんが説明して下さった内容についてです。
> 質問文を見る限り、どちらも
>   Dim c As Integer = DataGrid1.SelectedRows.Count
> といった同じコードを意味する内容に見えたのですが、
> それぞれの違いは何なのでしょうか?
>
> 一方が Rows の書き間違いであったとか、あるいはそれぞれの行を、
> 別のイベントで値を取得しているといった話でも無いのだとすると、
> クイックウォッチで確認するたびに、結果が 1 と 0 の間で
> 交互に変化するという事なのでしょうか?
今、もう一度確認してみました。
valueが行番号用の変数なのですが、
value = DataGridView1.SelectedRows.Countとすると、値は0と1が交互ではありませんが、変化します。(値が0のときのエラーログもあるので、間違いないと思います。)ちょっと気になったのが、値の1が赤字になっていたということです。
value = DataGridView1.Rows.Item(0).Index + 1 として
DataGridView1の中身をウォッチでみると、
SelectedRows.Countの値は1です。
currentrow.cells.countの値はちゃんと列数分だけの正しい値になっています。

昨日までは、DataGridView1の青く反転した行の1つめのセルの外枠が点線ではなかったのに、今日は、点線表示(currentcellを示す?)になる場合も出てきました。何度もやっているとまた点線表示はなくなります。
>値の設定ができるかどうかという違いがよくわかりません。

値が設定できる=値を設定することで、設定した値の行数にする事が出来ある。

値が設定出来ない=リードオンリー。

>value = DataGridView1.SelectedRows.Countとすると、値は0と1が交互ではありませんが、変化します。

MultiSelectがFlaseの場合、複数行の選択は出来ないため、1行か0行の選択しか出来ません。
0行選択の場合は、行を選択していないと言うことです。



もう一度初めに戻りましょう。

>画面表示直後に「1/500」などというように表示するにはどのようにしたらよいでしょうか?

この「1」は選択されている行番号でよろしいでしょうか?

であれば、DataGridView1.SelectedRows.Count が1の時に、DataGridView1.SelectedRows(0).Index + 1 で求められるはずです。


この「500」は全行数でよろしいでしょうか?

であれば、DataGridView1.RowCount または、 DataGridView1.Rows.Count で求められます。
ヴァンさん、お返事ありがとうございます。

> 値が設定できる=値を設定することで、設定した値の行数にする事が出来ある。
> 値が設定出来ない=リードオンリー。
なるほど!設定出来ないとはリードオンリーということだったのですね。

> MultiSelectがFlaseの場合、複数行の選択は出来ないため、1行か0行の選択しか出来ません。
> 0行選択の場合は、行を選択していないと言うことです。
そうなんです。フォームオープン時は行選択状態にならない(ときがある)のが、問題なのです。

> であれば、DataGridView1.SelectedRows.Count が1の時に、DataGridView1.SelectedRows(0).Index + 1 で求められるはずです。
残念ながら、今の状態はDataGridView1.SelectedRows.Count が0になり、
DataGridView1.SelectedRows(0).Index + 1は、「indexが範囲を超えています」
というエラーになります。

> であれば、DataGridView1.RowCount または、 DataGridView1.Rows.Count で求められます。
DataGridView1.Rows.Countの方はいつも同じ値で、全件数を表示しています。
>>であれば、DataGridView1.SelectedRows.Count が1の時に、DataGridView1.SelectedRows(0).Index + 1 で求められるはずです。
> 残念ながら、今の状態はDataGridView1.SelectedRows.Count が0になり、
> DataGridView1.SelectedRows(0).Index + 1は、「indexが範囲を超えています」
> というエラーになります。

DataGridView1.SelectedRows.Count が0と言うことは選択された状態で無いということです。
なので、DataGridView1.SelectedRows(0)は成り立たなくなり、NULL値になります。
なので、DataGridView1.SelectedRows(0).Indexでアクセスするとエラーになります。

DataGridView1.SelectedRows.Countが1の時にアクセスできるのです。
■No24452に返信(satsukiさんの記事)
>>> アクティブセルがないので、selectedrows.countやcurrentrow.cells.countが0になるのですね。
>> そんなハズはありません。
> 私のコードはDataGridView1.DataSourceにdatatable1が設定してあるので、NullReferenceExceptionにはならないようです。

dataTable1 が設定してあろうとなかろうと、
『アクティブセルが無い場合』には、CurrentRow は Nothing となります。

もし例外が発生しないのであれば、それは CurrentRow が Nothing では
無い状態であるはずで、それは「アクティブセルが存在している」状態だと思います。


また、DataGridView1.CurrentRow.Cells.Count が 0 になるということは、
列数=0、行数≠0 な状態を作り出さねばならないと思いますが、DataGridView では
そのような状態を作り出せなかったように思います。


> Public Sub Initialize○○○()というプロシージャの中に書かれており、Loadイベントではありません。
「現在位置の行番号」を取得したいのであれば、この値を更新するタイミングは、
別の行に移動した時、すなわち RowEnter イベントなどが適切かと思います。

また、RowEnter イベントを使うのであれば、移動後の行番号は、イベント引数から
得る事ができます。すなわち、このような形です。

Private Sub DataGridView1_RowEnter(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles DataGridView1.RowEnter
 Label1.Text = CStr(e.RowIndex)
End Sub


>>Rows.Count と RowCount は、値の設定ができるかどうかという違いがあります。
>>取得する時点においては、Rows.Count と RowCount は同義です。
>>ただし件数の取得だけであれば、RowCount の方がパフォーマンスは上です。
> 値の設定ができるかどうかという違いがよくわかりません。

既に回答が付いていますが、Rows.Count は読み込み専用であるという意味です。

たとえば先の私のコードでは、総行数を 0 にするために、
 DataGridView1.RowCount = 0
と、0 を「設定」していますよね。しかしこれを、
 DataGridView1.Rows.Count = 0
と記述することはできない、という意味です。


> value = DataGridView1.SelectedRows.Countとすると、値は0と1が交互ではありませんが、変化します。
どういう時に 0 になり、どういう時に 1 になるのかを確認されていますか?

選択されている行が無い状態であれば、当然、その値は 0 になりますし、
どこかの行が選択されていれば、1 が返されます。

また、設定を MultiSelect = True にしていた場合には、複数の行を
同時に選択できるため、この場合には、2 以上が返されることもあります。



> ちょっと気になったのが、値の1が赤字になっていたということです。
値が赤くなるのは、直前に実行された処理によって、
その値が変化したという事を意味します。

ところで、赤になっていたのは、「クイックウォッチ」ウィンドウではなく、
「ウォッチ」ウィンドウの方ではありませんでしたか?


> value = DataGridView1.Rows.Item(0).Index + 1 として
この結果は、常に 1 を返しますね。
DataGridView1.Rows.Item(n).Index は、常に n を返しますから。

ただし「n < 総行数」で無い場合には、例外 ArgumentOutOfRangeException が発生します。


> DataGridView1の中身をウォッチでみると、
> SelectedRows.Countの値は1です。
> currentrow.cells.countの値はちゃんと列数分だけの正しい値になっています。

SelectedRows.Count が 1 の時は、そうなると思います。

そして、SelectedRows.Count が 0 の場合には、
CurrentRow.Cells は、エラーとなるはずです。
魔界の仮面弁士さん、ご返事ありがとうございます。

> もし例外が発生しないのであれば、それは CurrentRow が Nothing では
> 無い状態であるはずで、それは「アクティブセルが存在している」状態だと思います。
そんな気がしてきました。

> また、DataGridView1.CurrentRow.Cells.Count が 0 になるということは、
> 列数=0、行数≠0 な状態を作り出さねばならないと思いますが、DataGridView では
> そのような状態を作り出せなかったように思います。
なるほど。見間違いをしたのでしょうか?


> 「現在位置の行番号」を取得したいのであれば、この値を更新するタイミングは、
> 別の行に移動した時、すなわち RowEnter イベントなどが適切かと思います。
>
> また、RowEnter イベントを使うのであれば、移動後の行番号は、イベント引数から
> 得る事ができます。すなわち、このような形です。
>
> Private Sub DataGridView1_RowEnter(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles DataGridView1.RowEnter
>  Label1.Text = CStr(e.RowIndex)
> End Sub
この方法は簡単そうでよいですね。
Public Sub Initialize○○○()は、フォームがオープンされるときのプロシージャで、行選択したときの行番号の値取得は、別で行っています。
全く開いただけの状態での行番号の取得(つまり1行目)ができればよいのです。

> 既に回答が付いていますが、Rows.Count は読み込み専用であるという意味です。
>
> たとえば先の私のコードでは、総行数を 0 にするために、
>  DataGridView1.RowCount = 0
> と、0 を「設定」していますよね。しかしこれを、
>  DataGridView1.Rows.Count = 0
> と記述することはできない、という意味です。
理解できました。

> どういう時に 0 になり、どういう時に 1 になるのかを確認されていますか?
> 選択されている行が無い状態であれば、当然、その値は 0 になりますし、
> どこかの行が選択されていれば、1 が返されます。
上でも書きましたように、全くフォームを開くだけの状態の行番号取得について、
エラーが出たり出なかったりします。

> ところで、赤になっていたのは、「クイックウォッチ」ウィンドウではなく、
> 「ウォッチ」ウィンドウの方ではありませんでしたか?
そうでした。ウォッチの方です。
■No24454に返信(satsukiさんの記事)
> そうなんです。フォームオープン時は行選択状態にならない(ときがある)のが、問題なのです。

やりたい事は、
>>>> 現在位置の行番号と行の総数を/で区切って表示したい
でしたよね。
であれば、そもそもフォームオープン時に取得する必要はなく、
行が変化した時にのみ、表示を切り替えれば良いのでは無いでしょうか。

また、フォームオープン時であろうとなかろうと、「現在の行」が
存在しない状態はありえます(特に、データが 0 件の場合)。
その場合、どのように表示したいのかを決めておいてください。

>>であれば、DataGridView1.SelectedRows.Count が1の時に、DataGridView1.SelectedRows(0).Index + 1 で求められるはずです。
> 残念ながら、今の状態はDataGridView1.SelectedRows.Count が0になり、
> DataGridView1.SelectedRows(0).Index + 1は、「indexが範囲を超えています」
> というエラーになります。

ヴァンさんの投稿を読み返してみてください。0 の時ではなく、
「.SelectedRows.Count が1の時に」と書いていますよね。

ですから、
  Dim rows As DataGridViewSelectedRowCollection
  rows = DataGridView1.SelectedRows
  If rows.Count > 0 Then
    Label1.Text = CStr(rows(0).Index + 1)
  Else
    '選択されていない時の表現
    Label1.Text = "行が選択されていません。"
  End If
のように、何らかの判定が必要になるということです。


ただし先に記述したように、現在の行位置を取得するためだけに
SelectedRows を取得すべきではありません。CurrentCellAddress を
利用するか、RowEnter イベント等の引数から得るようにしましょう。
http://msdn.microsoft.com/ja-jp/library/ha5xt0d9.aspx
魔界の仮面弁士さん、お返事ありがとうございます。

> であれば、そもそもフォームオープン時に取得する必要はなく、
> 行が変化した時にのみ、表示を切り替えれば良いのでは無いでしょうか。
フォームオープン時に1/○○○としたいので、オープン時にも必要かと
思いました。

> また、フォームオープン時であろうとなかろうと、「現在の行」が
> 存在しない状態はありえます(特に、データが 0 件の場合)。
> その場合、どのように表示したいのかを決めておいてください。
そうですね。「現在の行」が存在しない状態がありえるので、
場合によって分岐させればよいのですね。

> ヴァンさんの投稿を読み返してみてください。0 の時ではなく、
> 「.SelectedRows.Count が1の時に」と書いていますよね。
> ですから、
>   Dim rows As DataGridViewSelectedRowCollection
>   rows = DataGridView1.SelectedRows
>   If rows.Count > 0 Then
>     Label1.Text = CStr(rows(0).Index + 1)
>   Else
>     '選択されていない時の表現
>     Label1.Text = "行が選択されていません。"
>   End If
> のように、何らかの判定が必要になるということです。
本日朝いちばんでやってみたところ、
DataGridView1のcurrentrow.cells.countの値はきちんと列数分の値になっており、selectedrows.countの値は1になっています。
要は、場合にわけて、上記値が取得できなかった場合のコードを記述しておけば
よいということですね。

> ただし先に記述したように、現在の行位置を取得するためだけに
> SelectedRows を取得すべきではありません。CurrentCellAddress を
> 利用するか、RowEnter イベント等の引数から得るようにしましょう。
> http://msdn.microsoft.com/ja-jp/library/ha5xt0d9.aspx
Dim selectedRowCount As Integer = DataGridView1.Rows.GetRowCount(DataGridViewElementStates.Selected)
の値を見てみましたら、これも1になっています。
なるほど、コレクションやプロパティにアクセスするとパフォーマンスが下がり、
メソッドの方がよいということなんですね。
ヘルプの内容は少し難しいですが、勉強になりました。パフォーマンスも考えて
コードを書くのが大事だとわかりました。ありがとうございました。
解決済み!
2009/04/28(Tue) 11:03:55 編集(投稿者)

■No24460に返信(satsukiさんの記事)
>>であれば、そもそもフォームオープン時に取得する必要はなく、
>>行が変化した時にのみ、表示を切り替えれば良いのでは無いでしょうか。
> フォームオープン時に1/○○○としたいので、オープン時にも必要かと
> 思いました。

それは、最初の行位置を 1 固定にしたいという意味では無いですよね。
データ件数が 0 件だったら、1 行目は存在しないわけですから。


で、ひとつ注意。フォームがロードされていても、DataGridView のロードが
完了していない事がありえる事に注意してください。たとえば下記のように、
DataGridView を TabControl/TabPage の上に配置していた場合などには、
最初にそのタブが表示されるまで、DataGridView は作成されません。


'★コントロールを何も貼っていない、空のフォーム上で実行してみてください★
Public Class Form1
 Private WithEvents label1 As Label
 Private WithEvents table As DataTable
 Private WithEvents dgv1, dgv2, dgv3 As DataGridView
 Private WithEvents tabControl1 As TabControl
 Private WithEvents tabPage1, tabPage2 As TabPage

 Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
  CreateSampleControls()
  UpdatePositionLabel()
 End Sub

 Private Sub dgv1_RowEnter(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) _
    Handles dgv1.RowEnter, dgv2.RowEnter, dgv3.RowEnter
  UpdatePositionLabel()
 End Sub

 Private Sub UpdatePositionLabel()
  '「現在の行位置/総行数」
  label1.Text = String.Format("dgv1={0,4}/{1,4}|dgv2={2,4}/{3,4}|dgv3={4,4}/{5,4}", _
   dgv1.CurrentCellAddress.Y + 1, dgv1.RowCount, _
   dgv2.CurrentCellAddress.Y + 1, dgv2.RowCount, _
   dgv3.CurrentCellAddress.Y + 1, dgv3.RowCount).Replace("|", vbNewLine)

  'DataGridView が作成されているか?
  Me.Text = String.Format("{0}, {1}, {2}", dgv1.Created, dgv2.Created, dgv3.Created)
 End Sub

 Private Sub CreateSampleControls()
  Me.SuspendLayout()
  label1 = New Label()
  label1.AutoSize = True
  label1.Location = New Point(280, 30)
  label1.Text = "Label1"
  Controls.Add(label1)

  table = New DataTable()
  table.Columns.Add("Col1")
  table.Columns.Add("Col2")
  For r As Integer = 1 To 100
   table.Rows.Add(String.Format("{0:00}-1", r), String.Format("{0:00}-2", r))
  Next

  tabControl1 = New TabControl()
  tabPage1 = New TabPage("Tab1")
  tabPage2 = New TabPage("Tab2")
  tabControl1.TabPages.AddRange(New TabPage() {tabPage1, tabPage2})
  tabControl1.SetBounds(0, 200, 300, 200)
  Controls.Add(tabControl1)

  dgv1 = New DataGridView()
  dgv2 = New DataGridView()
  dgv3 = New DataGridView()
  dgv1.TopLeftHeaderCell.Value = "dgv1"
  dgv2.TopLeftHeaderCell.Value = "dgv2"
  dgv3.TopLeftHeaderCell.Value = "dgv3"
  dgv1.SelectionMode = DataGridViewSelectionMode.FullRowSelect
  dgv2.SelectionMode = DataGridViewSelectionMode.FullRowSelect
  dgv3.SelectionMode = DataGridViewSelectionMode.FullRowSelect
  dgv1.SetBounds(0, 0, 250, 170)
  dgv2.SetBounds(0, 0, 250, 170)
  dgv3.SetBounds(0, 0, 250, 170)
  dgv1.DataSource = table
  dgv2.DataSource = table
  dgv3.DataSource = table
  Controls.Add(dgv1)
  tabPage1.Controls.Add(dgv2)
  tabPage2.Controls.Add(dgv3)

  Me.Size = New Size(400, 450)
  Me.ResumeLayout()
 End Sub
End Class




> 要は、場合にわけて、上記値が取得できなかった場合のコードを記述しておけば
> よいということですね。
ですます。

.CurrentCell のように「Nothing を返す可能性があるプロパティ/メソッド」を
扱う場合には、事前に Nothing 判定を行っておいて方が安全ですし、また、
.Rows(0) などのような物についても、その 0 という値が本当に使用可能かどうかを
確認するようにした方が良いでしょう。


>>ただし先に記述したように、現在の行位置を取得するためだけに
>>SelectedRows を取得すべきではありません。CurrentCellAddress を
>>利用するか、RowEnter イベント等の引数から得るようにしましょう。
>>http://msdn.microsoft.com/ja-jp/library/ha5xt0d9.aspx
> Dim selectedRowCount As Integer = DataGridView1.Rows.GetRowCount(DataGridViewElementStates.Selected)
> の値を見てみましたら、これも1になっています。
> なるほど、コレクションやプロパティにアクセスするとパフォーマンスが下がり、
> メソッドの方がよいということなんですね。

微妙に間違っていますが、まぁ、そんなところです。

ただ、「プロパティにアクセスするとパフォーマンスが下がる」というわけでは
ありません。そもそも、Rows や CurrentCellAddress もプロパティですしね。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板