SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

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に入力すると、
以下のように入力値の検証エラー時の赤い枠が表示されます。
f:id:minami_SC:20140511201624p:plain



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で追加になった方法。
ちょっと長くなったので、この方法は次回にまとめます。