注意:DataGridViewコントロールは、.NET Framework 2.0で新しく追加されました。
ユーザーがセルに入力した値が正しいかどうかを調べ、正しくなければ入力をキャンセルするには、CellValidatingイベントを使用します。CellValidatingイベントハンドラでセルの内容が妥当かを調べ、不正であればユーザーに注意をしたり、前の値に戻したり、正しい値が入力されるまでフォーカスが移動しないようにしたりすることができます。
CellValidatingイベントはそのセルが入力フォーカスを失う時に発生しますので、現在のセルが変わる時や、他のコントロールにフォーカスが移る時に発生します。
以下に示す例では、"Column1"列のセルが空である時、その行にエラーテキストを設定して、別のセルにフォーカスが移らないようにしています。
'CellValidatingイベントハンドラ Private Sub DataGridView1_CellValidating(ByVal sender As Object, _ ByVal e As DataGridViewCellValidatingEventArgs) _ Handles DataGridView1.CellValidating Dim dgv As DataGridView = DirectCast(sender, DataGridView) '新しい行のセルでなく、セルの内容が変更されている時だけ検証する If e.RowIndex = dgv.NewRowIndex OrElse Not dgv.IsCurrentCellDirty Then Exit Sub End If If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _ e.FormattedValue.ToString() = "" Then '行にエラーテキストを設定 dgv.Rows(e.RowIndex).ErrorText = "値が入力されていません。" '入力した値をキャンセルして元に戻すには、次のようにする 'dgv.CancelEdit() 'キャンセルする e.Cancel = True End If End Sub 'CellValidatedイベントハンドラ Private Sub DataGridView1_CellValidated(ByVal sender As Object, _ ByVal e As DataGridViewCellEventArgs) _ Handles DataGridView1.CellValidated Dim dgv As DataGridView = DirectCast(sender, DataGridView) 'エラーテキストを消す dgv.Rows(e.RowIndex).ErrorText = Nothing End Sub
//CellValidatingイベントハンドラ private void DataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { DataGridView dgv = (DataGridView)sender; //新しい行のセルでなく、セルの内容が変更されている時だけ検証する if (e.RowIndex == dgv.NewRowIndex || !dgv.IsCurrentCellDirty) { return; } if (dgv.Columns[e.ColumnIndex].Name == "Column1" && e.FormattedValue.ToString() == "") { //行にエラーテキストを設定 dgv.Rows[e.RowIndex].ErrorText = "値が入力されていません。"; //入力した値をキャンセルして元に戻すには、次のようにする //dgv.CancelEdit(); //キャンセルする e.Cancel = true; } } //CellValidatedイベントハンドラ private void DataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e) { DataGridView dgv = (DataGridView)sender; //エラーテキストを消す dgv.Rows[e.RowIndex].ErrorText = null; }
CellValidatingイベントハンドラには、DataGridViewCellValidatingEventArgsオブジェクトが渡されます。基本的にはこのFormattedValueプロパティを検査することにより、正しい値であるかを判断します。ただしこの値は、表示用の書式指定済みの値であり、セルの本当に値ではありません。
CancelプロパティをTrueにすることにより、セルに入力された値を確定しないようにします。この時、現在のセルが別のセルに移動できなくなりますし、基本的には他のコントローラの操作や、フォームの閉じるボタン(Xボタン)も無効になります。
行のErrorTextプロパティを使用して、その行のヘッダーセルにエラーアイコンを表示しています。エラーアイコンについては、こちらで説明しています。
補足:編集中のセルにはエラーアイコンが表示されないため、上記の例でセルのErrorTextプロパティにエラーテキストを設定しても、エラーアイコンが表示されません。編集中のセルにエラーアイコンを表示する方法は、「How do I show the error icon when the user is editing the cell?(リンク切れのため、Internet Archiveへのリンク)」で説明されています。
このエラーテキストは適当なタイミング(正しい値が入力された時)で消す必要があります。CellValidatedやCellEndEditイベントハンドラで消すのが適当でしょう。上記の例では、CellValidatedイベントを使用しています。
そのセルの内容だけでなく、同じ行の別のセルの内容によって検証結果が異なるケースでは、CellValidatingイベントではなく、RowValidatingイベントを使うとよいでしょう。RowValidatingイベントはCellValidatingイベントと違い、同じ行の別のセルにフォーカスが移動しても発生せず、別の行や、別のコントロールに移動するときに発生します。よって、同じ行のセルを一度に検証したい時に便利です。
以下の例では、空のセルがあると別の行に移動できないようにしています。
'RowValidatingイベントハンドラ Private Sub dataGridView1_RowValidating(ByVal sender As Object, _ ByVal e As DataGridViewCellCancelEventArgs) _ Handles DataGridView1.RowValidating Dim dgv As DataGridView = DirectCast(sender, DataGridView) '新しい行でなく、行の内容が変更されている時だけ検証する If e.RowIndex = dgv.NewRowIndex OrElse Not dgv.IsCurrentRowDirty Then Exit Sub End If '行のセルが空かを調べる For Each cell As DataGridViewCell In dgv.Rows(e.RowIndex).Cells If cell.Value Is Nothing OrElse cell.Value.ToString() = "" Then '行にエラーテキストを設定 dgv.Rows(e.RowIndex).ErrorText = _ "すべてのセルに値を入力してください。" 'キャンセルする e.Cancel = True End If Next End Sub 'RowValidatedイベントハンドラ Private Sub dataGridView1_RowValidated(ByVal sender As Object, _ ByVal e As DataGridViewCellEventArgs) _ Handles DataGridView1.RowValidated Dim dgv As DataGridView = DirectCast(sender, DataGridView) 'エラーテキストを消す dgv.Rows(e.RowIndex).ErrorText = Nothing End Sub
//RowValidatingイベントハンドラ private void dataGridView1_RowValidating(object sender, DataGridViewCellCancelEventArgs e) { DataGridView dgv = (DataGridView)sender; //新しい行でなく、行の内容が変更されている時だけ検証する if (e.RowIndex == dgv.NewRowIndex || !dgv.IsCurrentRowDirty) { return; } //行のセルが空かを調べる foreach (DataGridViewCell cell in dgv.Rows[e.RowIndex].Cells) { if (cell.Value == null || cell.Value.ToString() == "") { //行にエラーテキストを設定 dgv.Rows[e.RowIndex].ErrorText = "すべてのセルに値を入力してください。"; //キャンセルする e.Cancel = true; } } } //RowValidatedイベントハンドラ private void dataGridView1_RowValidated(object sender, DataGridViewCellEventArgs e) { DataGridView dgv = (DataGridView)sender; //エラーテキストを消す dgv.Rows[e.RowIndex].ErrorText = null; }
CellValidatingとRowValidatingイベントの発生する順番は、CellValidating、CellValidated、RowValidating、RowValidatedとなります。
CellValidatingイベントでセルに不正な値が入力されないようにチェックしていたとしても、セルに不正な値が設定される可能性があります。プログラムでセルに直接値を設定した場合は言うまでもありませんが、それ以外にも、新しい行が追加された時に不正な値が設定される恐れがあります。
例えば、一番初めに紹介したCellValidatingイベントを使ったサンプルコードのケースでは、新しい行の"Column1"以外のセルに値を入力して新しい行を作成した時、"Column1"のセルにはフォーカスが移動していませんので、このセルのCellValidatingイベントは発生しません。そのため、新しい行の"Column1"のセルの初期値が不正な値であったならば、不正な値のまま新しい行が追加されてしまいます。
これを防ぐには、「DataGridViewに新しく追加される行のセルの既定値を指定する」で紹介したような方法でセルの既定値が不正な値にならないようにしたり、RowValidatingイベントでチェックを行うようにすればよいでしょう。