C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: データグリッドビューの表示(行選択)が思うようになりません


(過去ログ 177 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■101506 / inTopicNo.1)  データグリッドビューの表示(行選択)が思うようになりません
  
□投稿者/ kitakitune (1回)-(2023/03/07(Tue) 13:25:18)

分類:[.NET 全般] 

2023/03/07(Tue) 13:28:16 編集(投稿者)

VB.NETでMySQLに接続するフォームアプリを作成しています。

アプリ内で作成したデータグリッドビューの行選択が(特定の条件の下で)思うように動作しません。

概要は以下のとうりです。
フォーム(以下MFとします)内に2つのDGVがあります。これをDGV1、DGV2とします。

DGV1の行には氏名の一覧を表示しています。
DGV2の行にDGV1で選択された人との取引内容を、時間順(昇順)に表示します。

DGV2のプロパティでは
AllowUserToAddRowsをtrue に
SelectionMode = FullRowSelect に設定しています。
DGV2の最下行はデータのない空白行で、最下行が選択された状態にしたいのです。

MFのコンストラクタでDBに接続しDGV1、DGV2を作成・表示しています。(“初期状態”とします。)
初期状態では
DGV1は先頭行を選択し、それに応じた内容をDGV2に表示して、
DGV2の選択行は最下行に設定しているのですが
DGV2の行選択が最下行のひとつ前の行になってどうしても最下行が選択された状態になりません。

顧客の選択(変更)はDGV1のセルクリックイベントで捉えています。
DGV1の行をクリックするたびに、DBに問い合わせDGV2の内容を変更する仕様です。

DGV1の行をクリックして、DGV2のデータを取り込むごとに、
DGV2行選択を
DGV2.CurrentCell = DGV2.Rows.(DGV2.Rows.Count &#8211; 1).Cells(0)
として最下行に設定しています。

初期状態では(MFのコンストラクタでは)DGV1をクリックする代わりに
まず、DGV1を編集し DGV1の一行目のデータを参照してDBに問い合わせ
それに応じた DGV2の内容を編集しています。

実際にDGV1をクリックしてDGV2を編集した時の動作には問題ありません。
(最下行 空白の行が選択されます。)
不具合は前述の初期状態のときのみの現象です。

ちなみに、初期状態でDGV1の選択を変えずに(先頭行が選択されている状態のままで)
DGV1をクリックすると、クリックイベントが実行されDGV2の内容はそのままで最下行が選択された状態になります。
また、初期状態以後DGV1をクリックしてDGV1の選択行を変更したときの
DGV2の表示と最下行選択には問題ありません。

初期状態での行インデックスを調べてみてもインデックスの値は最下行を示しています。
また、ソース上からはクリックイベントを発生させられないと思い、
Private Sub DGV2_ini() をして定義しDGV1のクリックイベントをコピペして初期状態を作成した後に実行して(クリックしたつもり)みたりもしましたが思うようになりません。
DGV2の行選択(DGV2.CurrentCellの設定)をいろいろなタイミングに変えてみたりしても、(初期状態では)DGV2の選択行のインデックスと行の選択状態が思うようになっていません。
(選択しているセルのインデックスは最下行なのに、選択行は最下行の一つ上の行になっている。)

長々と記述しましたが最後まで目を通していただきありがとうございます。
拙い文章で要領を得ない部分も多いかと思われますが、以上の記述で解決法(あるいは解決のためのヒントでも)
御教授いただけると幸いです。

引用返信 編集キー/
■101509 / inTopicNo.2)  Re[1]: データグリッドビューの表示(行選択)が思うようになりません
□投稿者/ 魔界の仮面弁士 (3581回)-(2023/03/07(Tue) 16:08:16)
No101506 (kitakitune さん) に返信
> DGV2.CurrentCell = DGV2.Rows.(DGV2.Rows.Count &#8211; 1).Cells(0)
> として最下行に設定しています。

&#8211; は「ダッシュ記号」ですね。全角マイナス記号と間違えた?
でもそれを抜きにしても、.Rows.(〜).Cells(0) だと文法違反になるような…?

新規行の選択なら、この場面で .Rows.Count の出番はなく、
 DGV2.CurrentCell = DGV2(0, DGV2.NewRowIndex)
だと思いますよ。厳密にいえば、上記はさらに
 If DGV2.ColumnCount > 0 AndAlso DGV2.AllowUserToAddRows Then
の事前チェックも必要なのですが、これらが常に True なのであれば判定も不要なはず。


> DGV1の行には氏名の一覧を表示しています。
> DGV2の行にDGV1で選択された人との取引内容を、時間順(昇順)に表示します。

取引内容が数百件程度までであれば、DataSet 内に「氏名一覧」テーブルと「取引内容」テーブルを
用意してデータを事前ロードしておき、両テーブルを DataRelation で繋ぐ方法もあります。
https://learn.microsoft.com/ja-jp/dotnet/api/system.data.dataset.relations?view=netframework-4.8

DGV1, DGV2 には、BindingSource を経由してそれぞれをリンクしておけば、
特に DGV1 のイベントなどを処理する必要はなく、DGV1 の選択状態に応じて、
DGV2 の内容が自動的に切り替わるようにできます。
https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/create-a-master-detail-form-using-two-datagridviews?view=netframeworkdesktop-4.8

まぁ、数万件レベルのデータだと現実的ではないので、現状通り、
DGV1 の選択状態に応じて、DGV2 に表示する値を、
その都度 MySQL に問い合わせる仕様になるでしょうけれどね。


> 実際にDGV1をクリックしてDGV2を編集した時の動作には問題ありません。
> (最下行 空白の行が選択されます。)
BindingSource を利用されていますか?

DGV2 が ReadOnly なのであれば、DataTable を直接バインドする形でも良いですが、
編集可能な形でデータバインドしている場合は、BindingSource を経由して
バインドした方が、選択行を管理しやすいかと思います。
(とはいえ、イベント制御等をさほど行っていないならば、直接バインドでも問題ないです)


> 不具合は前述の初期状態のときのみの現象です。
DataGridView がロードされる前に処理されている…という状況かもしれません。

たとえば、TabControl を貼っており、2 ページ目以降の TabPage 上に
DataGridView が貼ってあるような場合、TabPage2 がアクティブになるまでは
その上のコントロールがまだ生成されていないので、DataGridView などの
初期動作に影響を与えることがあります。

http://bbs.wankuma.com/index.cgi?mode=al2&namber=5245&KLOG=15#3
http://bbs.wankuma.com/index.cgi?mode=al2&namber=5245&KLOG=15#7
http://bbs.wankuma.com/index.cgi?mode=al2&namber=7001&KLOG=18#2
http://bbs.wankuma.com/index.cgi?mode=al2&namber=7749&KLOG=19#3


そちらの環境で、下記のケースでは新規行が選択されますか?

Public Class Form1
  Private ds As DataSet
  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ds = New DataSet()
    Dim tbl1 = ds.Tables.Add("T1")
    tbl1.Columns.Add("C1", GetType(Integer))
    tbl1.Columns.Add("C2", GetType(String))
    tbl1.PrimaryKey = New DataColumn() {tbl1.Columns("C1")}

    tbl1.Rows.Add(100, "あいうえお")
    tbl1.Rows.Add(200, "かきくけこ")
    tbl1.Rows.Add(300, "さしすせそ")

    ds.AcceptChanges()

    DataGridView1.AllowUserToAddRows = True
    DataGridView1.AutoGenerateColumns = True
    DataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect
    DataGridView1.DataSource = tbl1

    DataGridView1.CurrentCell = DataGridView1(0, DataGridView1.NewRowIndex)
  End Sub
End Class
引用返信 編集キー/
■101512 / inTopicNo.3)  Re[2]: データグリッドビューの表示(行選択)が思うようになりません
□投稿者/ kitakitune (2回)-(2023/03/07(Tue) 19:12:42)
No101509 (魔界の仮面弁士 さん) に返信
> ■No101506 (kitakitune さん) に返信
>>DGV2.CurrentCell = DGV2.Rows.(DGV2.Rows.Count &#8211; 1).Cells(0)
>>として最下行に設定しています。
>
> &#8211; は「ダッシュ記号」ですね。全角マイナス記号と間違えた?
> でもそれを抜きにしても、.Rows.(〜).Cells(0) だと文法違反になるような…?
>
> 新規行の選択なら、この場面で .Rows.Count の出番はなく、
>  DGV2.CurrentCell = DGV2(0, DGV2.NewRowIndex)
> だと思いますよ。厳密にいえば、上記はさらに
>  If DGV2.ColumnCount > 0 AndAlso DGV2.AllowUserToAddRows Then
> の事前チェックも必要なのですが、これらが常に True なのであれば判定も不要なはず。

DGV2.Rows(DGV2.Rows.Count - 1).Cells(0)
と記述したつもりでした。

データグリッドビューの行を選択状態にするには、
SelectionModeプロパティ を FullLowSelect として
選択行のセルを選択すればいいと理解していました。

.Rows.count は、(.Rows.count - 1) が最終行のインデックスになるから
DGV2.CurrentCell = DGV2.Rows(DGV2.Rows.Count -1).Cells(0)
としたわけです。
構文エラーはでていないのですが、御指摘の方法がスマートだと思います。

行指定については見直して御指摘の方法にしようと思います。

>>DGV1の行には氏名の一覧を表示しています。
>>DGV2の行にDGV1で選択された人との取引内容を、時間順(昇順)に表示します。
>
> 取引内容が数百件程度までであれば、DataSet 内に「氏名一覧」テーブルと「取引内容」テーブルを
> 用意してデータを事前ロードしておき、両テーブルを DataRelation で繋ぐ方法もあります。
> https://learn.microsoft.com/ja-jp/dotnet/api/system.data.dataset.relations?view=netframework-4.8
>
> DGV1, DGV2 には、BindingSource を経由してそれぞれをリンクしておけば、
> 特に DGV1 のイベントなどを処理する必要はなく、DGV1 の選択状態に応じて、
> DGV2 の内容が自動的に切り替わるようにできます。
> https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/controls/create-a-master-detail-form-using-two-datagridviews?view=netframeworkdesktop-4.8
>
> まぁ、数万件レベルのデータだと現実的ではないので、現状通り、
> DGV1 の選択状態に応じて、DGV2 に表示する値を、
> その都度 MySQL に問い合わせる仕様になるでしょうけれどね。
>
そのような方法が有ることを知りませんでした。
とても便利そうなので調べて使ってい見ようと思います
>
>>実際にDGV1をクリックしてDGV2を編集した時の動作には問題ありません。
>>(最下行 空白の行が選択されます。)
> BindingSource を利用されていますか?

していません。
というか、そのような機能も知りませんでした。
調べてみます。

>
> DGV2 が ReadOnly なのであれば、DataTable を直接バインドする形でも良いですが、
> 編集可能な形でデータバインドしている場合は、BindingSource を経由して
> バインドした方が、選択行を管理しやすいかと思います。
> (とはいえ、イベント制御等をさほど行っていないならば、直接バインドでも問題ないです)
>
>
とても便利な機能だと思われます。
調べて使ってみます。
(DB からデータを datatabl に fill してときは、
そのデータをフォーム上の指定のラベルにバインドして表示する処理は行っています。
同様の処理なのかなと今は想像しています。)

>>不具合は前述の初期状態のときのみの現象です。
> DataGridView がロードされる前に処理されている…という状況かもしれません。
>
> たとえば、TabControl を貼っており、2 ページ目以降の TabPage 上に
> DataGridView が貼ってあるような場合、TabPage2 がアクティブになるまでは
> その上のコントロールがまだ生成されていないので、DataGridView などの
> 初期動作に影響を与えることがあります。
>
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=5245&KLOG=15#3
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=5245&KLOG=15#7
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=7001&KLOG=18#2
> http://bbs.wankuma.com/index.cgi?mode=al2&namber=7749&KLOG=19#3

これが一番怪しそうです。
御指摘の通り、MFとDGVの間にTabControlがありDGVはTabControlの上にあります
問題のDGV1、DGV2はTabPage2にあります。

今一度、御指摘を踏まえて、検証してみます。
>
>
> そちらの環境で、下記のケースでは新規行が選択されますか?
>
> Public Class Form1
>   Private ds As DataSet
>   Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
>     ds = New DataSet()
>     Dim tbl1 = ds.Tables.Add("T1")
>     tbl1.Columns.Add("C1", GetType(Integer))
>     tbl1.Columns.Add("C2", GetType(String))
>     tbl1.PrimaryKey = New DataColumn() {tbl1.Columns("C1")}
>
>     tbl1.Rows.Add(100, "あいうえお")
>     tbl1.Rows.Add(200, "かきくけこ")
>     tbl1.Rows.Add(300, "さしすせそ")
>
>     ds.AcceptChanges()
>
>     DataGridView1.AllowUserToAddRows = True
>     DataGridView1.AutoGenerateColumns = True
>     DataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect
>     DataGridView1.DataSource = tbl1
>
>     DataGridView1.CurrentCell = DataGridView1(0, DataGridView1.NewRowIndex)
>   End Sub
> End Class

最終行が選択されました。

御丁寧なご返信ありがとうございました。
今の私には、一行の無駄もない御指摘・御教授だと思います。
御指摘の全てを一度に消化するのは今の私には手に余りますが、
一つ一つを無駄にしないようにします。

御返信遅れましたが、
本当にありがとうございました。

引用返信 編集キー/
■101513 / inTopicNo.4)  Re[3]: データグリッドビューの表示(行選択)が思うようになりません
□投稿者/ kitakitune (3回)-(2023/03/07(Tue) 20:01:11)
No101509 (魔界の仮面弁士 さん) に返信

問題が解決しました

フォームのロード時に

Tp02.Visible = True 'Dgv2 があるタブページ
Dgv2.Visible = True
Dgv2.CurrentCell = Dgv2.Rows(L1).Cells(0) '最終行指定

(L1 最終行のインデックス)

を実行することで思う動作が実現できました。

思いの外、早く解決したことをうれしく思っています。

(実際、どういう理屈でこうなったかもやもやした思いは残るのですが。)

外にも有用な御指摘頂きました。
全部に目を通します。

本当に、ありがとうございました。
引用返信 編集キー/
■101518 / inTopicNo.5)  Re[4]: データグリッドビューの表示(行選択)が思うようになりません
□投稿者/ kitakitune (4回)-(2023/03/08(Wed) 12:02:49)
No101513 (kitakitune さん) に返信
> ■No101509 (魔界の仮面弁士 さん) に返信
>
> 問題が解決しました
>
> フォームのロード時に
>
> Tp02.Visible = True 'Dgv2 があるタブページ
> Dgv2.Visible = True
> Dgv2.CurrentCell = Dgv2.Rows(L1).Cells(0) '最終行指定
>
> (L1 最終行のインデックス)
>
> を実行することで思う動作が実現できました。
>
> 思いの外、早く解決したことをうれしく思っています。
>
> (実際、どういう理屈でこうなったかもやもやした思いは残るのですが。)
>
> 外にも有用な御指摘頂きました。
> 全部に目を通します。
>
> 本当に、ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -