WPFでの入力値検証
WPFでの入力値の検証(Validation)関係の機能の使い方を色々まとめてみました。
参考リンク集
以下の記事を参考にやってます。
MSDN Magazine: 入力の検証 - WPF で複雑なビジネス データの規則を適用する
WPFで入力値の検証を行うには、主に以下のような方法があります
- Binding Source側のプロパティで例外を投げる方法
- ValidationRuleを使う方法
- IDataErrorInfoを使う方法
- INotifyDataErrorInfoを使う方法(WPF4.5から追加)
Binding Source側のプロパティで例外を投げる方法
これはすごくシンプル。
ValidatesOnExceptionsプロパティをTrueにして、バインドしてるプロパティのSetterで例外が発生すると、検証エラーの通知が行われます。
たとえば、10文字以上の値をセットしようとすると例外を投げる、こんなプロパティを作っておき、
private string inputString; public string InputString { get { return inputString; } set { if (value.Count() > 10) throw new ArgumentException(); this.SetProperty(ref this.inputString, value); } }
XAML側で以下のように、ValidatesOnExceptions=Trueをセットすると、例外発生時に検証エラー通知が行われるようになります。
<TextBox Width="120" Height="23" Margin="50" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding InputString, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>
10文字以上の文字列をTextBoxに入力すると、
以下のように入力値の検証エラー時の赤い枠が表示されます。
ValidationRuleを使う方法
converterを作るのに似た方法。
ValidationRule派生クラスを作って、XAMLでデータバインドを設定する時に使用する。
ViewModelのレイヤー抜きで、View側だけで入力値の検証をしたい時に使うイメージかな。
まず、プロパティは、以下のように普通の実装にします。
文字数の上限などはVMでは意識しないようにしてます。
private string inputString; public string InputString { get { return inputString; } set { this.SetProperty(ref this.inputString, value); } }
そして、以下のようなValidationRule派生クラスを作成します。
public class StringLengthValidationRule : ValidationRule { public int MaxLength { get; set; } public StringLengthValidationRule() { MaxLength = 10; } public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { var v = value as string; if (v == null) return new ValidationResult(false, "input value should be a string"); if (v.Count() > MaxLength) return new ValidationResult(false, "string is larger than MaxLength"); return ValidationResult.ValidResult; } }
以下のように、XAML側でValidationRuleを設定すると、検証エラーの通知が行われます。
また、ValidationRule派生クラスを作る際に、上限文字数設定用のMaxLengthプロパティを作っておいたので、XAML側から、上限の文字数を設定できます。
<TextBox Width="120" Height="23" Margin="50" HorizontalAlignment="Left" VerticalAlignment="Top"> <TextBox.Text> <Binding Path="InputString" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:StringLengthValidationRule MaxLength="10"/> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox>
IDataErrorInfoを使う方法
WPF4.5ではINotifyDataErrorInfoが追加されたので、今後はこの方法はあまり使われなくなりそう。
でも、一応この方法も使ってみます。
以下のように、VMではIDataErrorInfoを実装します。
class MainWindowViewModel : BindableBase, IDataErrorInfo { private string inputString; public string InputString { get { return inputString; } set { this.SetProperty(ref this.inputString, value); } } public string Error { get { return string.Empty; } } public string this[string columnName] { get { return IsValid(columnName); } } private string IsValid(string propertyName) { switch (propertyName) { case "InputString": if (this.InputString.Count() > 10) return "string is larger than MaxLength"; break; default: break; } return string.Empty; } }
IDataErrorInfoを実装したら、インデクサで入力値の検証を行います。
プロパティ名が引数で渡されるので、プロパティごとの検証ロジックをIsValidメソッドで記述してます。
でXAMLでは、入力値の検証を行うプロパティに対して、ValidatesOnDataErrors=Trueをセットします。
<TextBox Width="120" Height="23" Margin="50" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding InputString, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
INotifyDataErrorInfoを使う方法
WPF4.5で追加になった方法。
ちょっと長くなったので、この方法は次回にまとめます。