DataGridViewを選択状態にする前にValidatingを挟みたいとき
今取り組んでいるシステムの画面は、上半分が一覧表、下半分が入力エリアというのがほとんどです。一番やりやすいのは入力画面を別にダイアログで表示するという方法らしいので、すでに失敗した感があるのですが、さらに、「一覧表へフォーカスが移動する前に入力項目をチェックし、変更があればユーザーに入力値を更新していいか確認する」という面倒な仕様が最近追加されました。
今日はValidatingイベントがTABキーによるフォーカス移動で発生したものか、それともマウスクリックによるフォーカス移動で発生したものかを区別する方法で悩んでいました。Validatingイベントを使用するのは、CancelEventArgsのCancelをtrueに設定するだけでフォーカスを前のコントロールに戻せるからです。しかしValidatingイベントの中からマウスなのかTABなのか判別するのは難しい。
今回は、GotFocusイベントとLostFocusイベントで対応することにしました。クリックしたときとタブキーで移動したときでは、イベントの発生順に違いがあるため、これを利用します。詳しくはこちら。リンク先にも「普通は使わない」とあるので、あまり良いやり方ではないかもしれません。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Diagnostics; namespace WindowsFormsApplication1 { public partial class FormFocus : Form { // DataGridView *1 // TextBox *1 // Button *1 // TextBoxが空欄の時、メッセージを表示して一覧を選択させない public FormFocus() { InitializeComponent(); this.textBox1.GotFocus += this.gotFocusEventHandler; this.textBox1.LostFocus += this.lostFocusEventHandler; this.button1.GotFocus += this.gotFocusEventHandler; this.button1.LostFocus += this.lostFocusEventHandler; } private void gotFocusEventHandler(object sender, EventArgs e) { // タブキー押下時のハンドラを登録 (sender as Control).Validating += this.validatingEventHandlerOnTab; } private void lostFocusEventHandler(object sender, EventArgs e) { if (sender == this.ActiveControl) { // senderとActiveControlが同じ=クリックによるLostFocus // Validatingイベントはこの後で発生するので、タブキー押下時の // イベントハンドラとクリック時のイベントハンドラを入れ替える (sender as Control).Validating -= this.validatingEventHandlerOnTab; (sender as Control).Validating += this.validatingEventHandlerOnClick; } } private void validatingEventHandlerOnClick(object sender, CancelEventArgs e) { if (ActiveControl is DataGridView) { Debug.WriteLine("ValidatingOnClick"); if (string.IsNullOrEmpty(this.textBox1.Text)) { MessageBox.Show("あかんよ"); e.Cancel = true; } } (sender as Control).Validating -= this.validatingEventHandlerOnClick; } private void validatingEventHandlerOnTab(object sender, CancelEventArgs e) { if (ActiveControl is DataGridView) { Debug.WriteLine("ValidatingOnTab"); if (string.IsNullOrEmpty(this.textBox1.Text)) { MessageBox.Show("あかんよ"); e.Cancel = true; } } (sender as Control).Validating -= this.validatingEventHandlerOnTab; } } }
自分ならこんな面倒な仕様は却下しますけど。