入力データ検証 その5 DataErrorValidationRule

一番初めのその1ではExceptionValidationRuleというValidationRuleを使用しました。これはバインドしているソースオブジェクトから例外がスローされた場合に検証不合格とするルールでした。これ以外に既定で用意されているValidationRuleとして今回はDataErrorValidationRuleをご紹介します。なお、DataErrorValidationRuleクラスは.NET Framework 3.5 SP1、および3.0 SP1から追加されたものです。


DataErrorValidationRuleはソースオブジェクトのIDataErrorInfoインターフェイス実装により発生するエラーをチェックするValidationRuleです。IDataErrorInfoインターフェイス.NET Framework 1.0の頃から存在しており、WindowsフォームやASP.NETの開発者にも馴染みのあるものです。たとえば、WindowsフォームのErrorProviderコントロールはIDataErrorInfoインターフェイス実装により発生したエラーに対応しています。


まずはいつものようにコードから見ていただこうと思います。


Window1.xaml

<Window x:Class="Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="Window1" Height="300" Width="300" FontSize="32">
    <Window.Resources>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="ToolTip"
                          Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
 
    <StackPanel>
 
        <TextBox Margin="30">
            <TextBox.Text>
                <Binding Path="ID">
                    <Binding.ValidationRules>
                        <DataErrorValidationRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
 
        <Button Content="Button" Margin="30"/>
 
    </StackPanel>
</Window>


上記のTextBox部分のBindingは下記のようにBinding.ValidatesOnDataErrorsプロパティをTrueに設定する書き方でも同様になります。
<TextBox Margin="30" Text="{Binding ID, ValidatesOnDataErrors=True}"/>


Window1.xaml.vb
Class Window1
 
    Sub New()
 
        ' この呼び出しは、Windows フォーム デザイナで必要です。
        InitializeComponent()
 
        ' InitializeComponent() 呼び出しの後で初期化を追加します。
        Me.DataContext = New DataSource()
    End Sub
 
End Class


DataSource.vb
Imports System.ComponentModel
 
Public Class DataSource
    Implements IDataErrorInfo
 
    Dim _id As Integer
 
    Public Property ID() As Integer
        Get
            ID = _id
        End Get
        Set(ByVal value As Integer)
            _id = value
        End Set
    End Property
 
    Public ReadOnly Property [Error]() As String Implements System.ComponentModel.IDataErrorInfo.Error
        Get
            Throw New NotImplementedException()
        End Get
    End Property
 
    Default Public ReadOnly Property Item(ByVal columnName As String) As String Implements System.ComponentModel.IDataErrorInfo.Item
        Get
 
            Dim result As String = Nothing
 
            If columnName = "ID" Then
                If (Me.ID < 0) Then
                    result = "IDは0以上の整数値を入力してください。"
                End If
            End If
 
            Return result
 
        End Get
    End Property
End Class




XAML部分については前回までに説明してきたことになりますので、特に問題ないかと思います。Buttonはフォーカスを遷移させるだけのために置いてあります。


IDataErrorInfoインターフェイスはErrorプロパティとItemプロパティ(インデクサ)を定義します。Errorプロパティはオブジェクト全体に関しての検証エラーを、Itemプロパティはオブジェクトの各プロパティ関しての検証エラーを返すプロパティです。実際にWPFのDataErrorValidationRuleで使用されるのはItemプロパティだけになります。


DataErrorValidationRuleを使用する方法の場合、検証ロジックはソースオブジェクト側に記述することになります。そのため、通常のバインディングプロセスのように


「ターゲットの変更」→「検証」→「変換」→「ソースへの反映」


ではなく、


「ターゲットの変更」→「変換」→「ソースへの反映」→「検証」


といった順番で最後に検証が行われます。
ソースへ値を反映した後でなければソース側で検証を行う際に値を確認できませんので、これは当然と言えば当然の動作になります。


ちなみにいつ検証を行うのかはValidationRule.ValidationStepプロパティで設定することができます。


Itemプロパティの実装はとても簡単です。インデクサのパラメータとして受けとるプロパティ名を判断して、そのプロパティが検証エラーならばStringでエラー内容を返します。


以上で、DataErrorValidationRuleのご紹介はおしまいです。次回は、カスタムのValidationRuleを作成する方法についてご紹介しようと思います。