C# WinForms DataGridView のクリック3アクション — 左クリック / 右クリック / ダブルクリックを分ける実装

みなさんこんにちは!ヒロポンです!

DataGridViewのクリックまわり地味にハマってる人めっちゃ多くない?

私の周りでも「CellClickイベントが全く起きないんだけどわかります?」とか、「CellClickで取った値をTextBoxに渡す方法がわかんないです」とか。。。CellEnterに悩まされてるって嘆いてる人や、「CellEnterとCellLeaveの動きが残念、Leaveのタイミングがズレてる」って愚痴ってる人も見かけます。

要するにクリック・セル移動の挙動が想像と違うってやつ。3アクション分岐の実装パターン1枚を手元に置いとけば、本来30分で終わる話なんですよね。

今回はDataGridViewのクリック3アクション(左/右/ダブルクリック)を分ける実装パターンを、verify-dotnet9で分岐ロジック動作確認しつつ並列展示します。

💡 DataGridViewの編集モード切替の基本 (ReadOnly / EditMode / RowValidatingの使い分け)は別記事 WinForms DataGridViewの編集モード完全ガイドで解説しました。今回はクリック分岐の応用編で、編集モードと組み合わせる時の罠も触れます。

💡 MenuStrip / ContextMenuStrip / ToolStripの使い分けは別記事 WinFormsメニュー3兄弟— MenuStrip / ToolStrip / ContextMenuStripの使い分けで解説しました。今回はDataGridView上での右クリック分岐に絞ります。

目次

忙しいあなたのために!最初にまとめ!!!

  • 3アクション分岐: ①左クリック(CellClick / CellContentClick) / ②右クリック(CellMouseDown + MouseButtons.Right判定+ ContextMenuStrip連携) / ③ダブルクリック(CellDoubleClick)
  • 全アクション共通のヘッダ判定 (if (e.RowIndex == -1) return;)を入れ忘れるとNullReferenceException
  • 右クリックはMouseDown + CurrentCell明示設定の二段実装がコツ
  • ダブルクリックは編集モード中(EditOnEnter / EditOnKeystroke)では編集確定にしか効かないので、編集モード解除のロジックを別途実装
  • Docker (verify-dotnet9)検証は分岐ロジックの言語仕様レベルのみ。DataGridView UI本体はWindows + Visual Studio実機環境で別途確認してください

以上!!!!!

補完関係— post 44 / post 57との位置付け

DataGridView関連記事は3本セットで読むと知識が広がるので、ついでに別タブ開いて後で呼んでおいてくださいませ!

記事 守備範囲 今回との関係
post 44 DataGridView編集モード完全ガイド 編集モード切替の基本はこちら (ReadOnly / EditMode / RowValidating) 今回H2「ダブルクリック」で前提として参照
post 57 WinFormsメニュー3兄弟 ContextMenuStripの使い分けはこちら (MenuStrip / ToolStrip / ContextMenuStrip) 今回H2「右クリック」で連携先として参照
今回(クリック3アクション分岐) クリック分岐の実装パターン post 44 / 57をくっつけて応用

3アクション比較表

3つのクリック種別をイベント/用途/実装難度/ハマりポイントの4軸で並べたのが下の表です。どうぞ!

DataGridViewクリック3アクション比較表

💡 PNGは視覚的な俯瞰用。「CellClick CellDoubleClick」「DataGridView右クリックCurrentCell」等の具体文字列で検索した時のSEOマッチ用に、同じ対応関係を下の表でも書きます。

クリック種別 イベント名 主な用途 実装難度 ハマりポイント
左クリック(単発) CellClick / CellContentClick 行選択・詳細画面オープン RowIndex==-1ヘッダ判定漏れ→ NullReferenceException
右クリック CellMouseDown + Button判定 コンテキストメニュー表示・削除確認 MouseDownとCellClickの競合→ CurrentCell明示設定が必要
ダブルクリック CellDoubleClick 編集モード切替・詳細展開 編集モード中のDoubleClickは編集確定にしか効かない

①左クリック— CellClick / CellContentClick

最も基本的なクリック分岐。

ヘッダ判定だけ気をつければシンプルです。

DataGridView左クリックの基本実装— CellClickイベント+ RowIndex==-1ヘッダ判定

CellClickCellContentClickの違い:

  • CellClick:セル領域内のどこでも発火(空白部分含む)
  • CellContentClick:セル内のコンテンツ(文字列・ボタン等)を直接クリックした時のみ発火

リンクセルやDataGridViewLinkColumnを使ってる場合はCellContentClickのほうが意図に近い動作になります。

②右クリック— CellMouseDown + ContextMenuStrip連携

業務SEが一番踏む罠の領域。

CellClick左クリックでしか発火しないので、右クリックはCellMouseDownで拾います。

DataGridView右クリックの実装— CellMouseDownでMouseButtons.Right判定+ CurrentCell明示設定+ ContextMenuStrip表示

ポイント:

  • 右クリックではdgv.CurrentCell自動更新されないので、明示的にCurrentCell = ...を呼ぶ
  • これを忘れると「右クリックしたセル」と「現在選択中のセル」が別物になって、メニューの削除確定で別の行を削除する事故が起きる
  • ContextMenuStrip.Show(dgv, ...)の座標はDataGridViewのクライアント座標に変換する必要あり

これがマジで罠の正体。

③ダブルクリック— CellDoubleClick +編集モード

最後、ダブルクリックで編集画面を開く/編集モードに切り替える実装。

DataGridViewダブルクリックの実装— CellDoubleClick +編集モード判定+別Form起動

詳細は WinForms DataGridViewの編集モード完全ガイド(post 44)で書いたEditModeの3パターン(EditOnEnter / EditOnKeystroke / EditProgrammatically)が前提です。

これも別タブで開いて一緒に読んでおいて!

EditOnEnterのままだとダブルクリックを編集モード切替に使えないので、デフォルトをEditProgrammaticallyにしておくのが定石。

ハマりポイント—そうじゃないケースが3つあります

ここまで「3イベント使い分ければいい」みたいに書いてきましたが、そうじゃないケースが3つあります

あなたのために特別に共有しておきます。

①ヘッダクリックでNullReferenceException

CellClickイベントハンドラを書いて、行データを取りに行く実装。ユーザーが列ヘッダをクリックした瞬間、dgv.Rows[e.RowIndex]e.RowIndex == -1になり、Rows[-1]NullReferenceExceptionが出てアプリが落ちる、というやつ。

私もある日、リリース後の業務系画面でユーザーがソート目的でヘッダをクリック →全画面落ちで「動かないんだけど」と内線がなんと飛んできて、背中に冷や汗。

速攻で修正したけど、、、ちょっと焦った

学び!!!全イベントハンドラの先頭にif (e.RowIndex == -1) return;を入れる。

IsNewRow判定も合わせて入れると新規行追加プレースホルダもスキップできて安全。

②右クリックでセル選択が動かない(CurrentCell競合)

CellMouseDownで右クリックを拾ってContextMenuStrip.Showする実装。メニューの「削除」をクリックすると別の行が削除される、という事象。

ユーザーは右クリックした行を削除したつもりが、実はその前に選択されていた行が消える。

経験ないですか??ありますよね。多分あるはず。

私もある月末バッチ画面で、ユーザーから「削除メニューが効かない」と報告を受けて、デバッガで追ったらCurrentCellが右クリック時に更新されてないことが原因と判明。

半日コードを追って気付いた事象で、終わってみれば1行の追加で済む話でした。

これもやらかしの原因。

学び!!! CellMouseDownで右クリックを判定したら、dgv.CurrentCell = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex]明示的に呼ぶ

これで右クリックでもセル選択が動き、メニューの削除確定が正しい行に効く。

③ EditMode=EditOnEnterでDoubleClickが編集確定にしか効かない

DataGridViewのEditModeをデフォルトのEditOnEnterのままにして、ダブルクリックで別Formを開こうとした時の話。CellDoubleClickイベントが発火しない

セルに進入した瞬間に編集モードに入っているため、ダブルクリックは編集セルの確定アクションとして消費される。

私もある日、後輩が組んだ画面で「ダブルクリック効きません」と相談を受けて、EditModeがEditOnEnterだったのに気付くまでなんと1時間かかった経験があります。

ダブルクリック動作よりも先に編集モードに入ってる、という構造を脳内モデルで持ってないと辿り着けない。

学び!!! DataGridViewのEditModeをデフォルトでEditProgrammaticallyにしておくのが定石。

編集モードに入るタイミングをdgv.BeginEdit(true)明示的に制御する。

これでダブルクリックを編集モード切替トリガとして自由に使える。

まとめ

DataGridViewのクリック3アクション分岐は、業務SEが画面リリース直前の仕様追加で一番焦る領域

ポイントを3つだけ!!!

  • 全イベントハンドラ先頭にif (e.RowIndex == -1) return;を入れる(ヘッダ判定)
  • 右クリックはCellMouseDown + CurrentCell明示設定の二段実装
  • ダブルクリックはEditModeをEditProgrammaticallyにして、編集モード制御を明示的に持つ

これで月末バッチ画面のリリース直前に「右クリック削除追加」を言われても、こんな感じで「ん??CurrentCell明示設定さえ忘れなければ30分で終わる」と即判断できるようになります!!!!

ぶっちゃけ、DataGridViewのクリック分岐はこんな感じで3イベントの優先順位を脳内で持っておくだけで、ユーザー要望に即対応できる業務SEになれます。

いい感じにこの雰囲気を知識として習得できると、次の現場でも資産として使えますよ!!

よくある質問

Q1. DataGridViewのヘッダクリックでNullReferenceExceptionが出るのはなぜですか?

A. CellClickイベントはヘッダクリック時も発火し、その時e.RowIndex == -1が返ります。

ヘッダ判定を入れずにdgv.Rows[e.RowIndex]にアクセスするとNullReferenceExceptionで落ちます。

冒頭でif (e.RowIndex == -1) return;を入れるのが鉄則です。詳細はハマりポイント①参照。

Q2. DataGridViewで右クリックしたセルが選択されません

A. CellMouseDownMouseButtons.Rightでも発火しますが、CurrentCellの更新は左クリックのみです。

右クリック時にdgv.CurrentCell = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex]を明示的に呼ぶと選択も連動します。詳細はハマりポイント②参照。

Q3.編集モード中のDoubleClickが編集確定にしか効かないのは仕様ですか?

A.そうです。

EditModeがEditOnEnterEditOnKeystrokeの場合、DoubleClickは編集セルの確定アクションとして消費されます。

編集モード解除のロジックをCellDoubleClickで別途実装するか、EditModeをEditProgrammaticallyにしてダブルクリックを編集モード切替トリガとして使う方法が定石です。

関連記事

以上!

この記事が気に入ったら
いいねしてね!

どんどんシェア待ってるぜ!!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次