DataGridView.CellValidating イベントで入力されたセルの値について、入力チェックをできますよね。
このイベントハンドラの引数の DataGridViewCellValidatingEventArgs.FormattedValue プロパティに編集中の値が入ります。
しかし、この FormattedValue プロパティは表示用の書式化(フォーマット)された後の値が入ってるんですよね。
たとえば、DataGridView で列の DefaultCellStyle.Format や、CellStyle.Format を通貨("c")として定義し、初期表示の値を 0 とするどうなるでしょうか。
ユーザに表示される値は ¥0 と表示されます。ここでユーザが ¥ を残したまま新たな数値を入れると CellValidating時は FormattedValue が ¥1000 や ¥1,000 になってしまいます。
別に、¥1000 や ¥1,000 という正しい書式なら DataTable にバインド時に勝手にCLRが面倒を見てくれるっぽいのですが、ユーザが 99¥1000 など、書式に反する値を入れると DataErr が発生してしてしまいます。
これを CellValidating 時にどう防ぐかで結構頭を悩ましました。
最初は書式化されてない値をなんとか取得できないかと考えました。
CellValidating 時はまだセルに値を入れる前なので、Cell.Value は古い値のままなので使えません。
しかし、この考え方(書式化されてない値を取得)はユーザが意図して正しい書式の値を入れた場合にはマズイということで却下。
書式化された値を数値にキャストできるかどうかでチェックするというアプローチに変えました。
そこで、登場したのは TryParse メソッド。このメソッドにはなんと書式化された文字列のチェックまでしてくれる機能があったのです。
詳しいことは 各数値型.TryParse のリファレンスをMSDNで見てもらうとわかりますが、要は TryParse の引数に (String, NumberStyles, IFormatProvider, 数値型 ) でオーバーロードしてるやつがあるということです。
NumberStyles で許可する書式を指定します。NumberStyles はビットフラグなので、論理和を取ってやれば複数の書式を指定可能にできます。
IFormatProvider はどのカルチャを使用するかを指定します。
ということで、グリッドで通貨列の入力チェックの例を上げてみます。
'dgvGrid は DataGridView'Money列のセルスタイルは通貨。 DefaultCellStyle.Format = "c"
Private Sub dgvGrid_CellValidating(ByVal sender As Object, ByVal e As DataGridViewCellValidatingEventArgs) _
Handles dgvGrid.CellValidating
Dim dgv As DataGridView = CType(sender, DataGridView)
'金額の入力チェック
If dgv.Columns(e.ColumnIndex).Name = "Money" Then
'TryPerseで許可する書式を指定(符号と、カンマと、通貨を許可)
Dim style As Globalization.NumberStyles = Globalization.NumberStyles.AllowLeadingSign Or Globalization.NumberStyles.AllowThousands Or Globalization.NumberStyles.AllowCurrencySymbol
'入力した値が数値にキャストできるかチェック。出来なければ不正な値とみなす。
If Not Decimal.TryParse(e.FormattedValue, style, Globalization.CultureInfo.CurrentCulture, 0) Then
MessageBox.Show("不正な書式です。正しい書式を入力してください。")
e.Cancel = True
End If
End If
End Sub