入力データの検証 その1

WPFにおける入力データの検証は、データバインディングのプロセスの1つとして行われます。





上の図はMSDNライブラリ データ バインディングの概要に掲載されているものと同じ図です。この図にあるように、検証はターゲットからソースへの値の転送中に発生します。


入力データ検証の第一歩となるサンプルを下記に示します。


DataSource.vb

Public Class DataSource
 
    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
 
End Class


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">
    <Viewbox>
        <StackPanel Height="100" Width="100">
 
            <TextBox Margin="10">
                <TextBox.Text>
                    <Binding Path="ID">
                        <Binding.ValidationRules>
                            <ExceptionValidationRule/>
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
 
            <Button Margin="10" Content="Focus to me."/>
        </StackPanel>
    </Viewbox>
</Window>


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


このサンプルを実行し、TextBoxに数字以外の値を入力してフォーカスを遷移させると下記の結果のようにTextBoxの周りに赤い枠線が表示されます。





このサンプルにおける検証のプロセスを説明します。


まず、TextBoxに値を入力した後にフォーカスを遷移させることで値が変更されたと判断され、ターゲットからソースへと値が転送されます。なお、値の変更タイミングについてはBinding.UpdateSourceTriggerプロパティの値で変更することが可能です。TextBoxのデフォルト値はLostFocusですが、PropertyChangedにすることでキー入力が発生するたびにターゲットからソースへ値が転送されます。


検証に合格しているのかそうでないのかは、バインドされている要素のValidation.Errors添付プロパティにValidationErrorが存在するかどうかで判断されます。値がターゲットから転送された後、Bindingに定義されているValidationRuleのValidateメソッドが実行され、それぞれのルールの検証が行われます。


サンプルで設定されているExceptionValidationRuleは単純に例外がスローされた場合に検証不合格とするルールです。Binding.UpdateSourceExceptionFilterプロパティにコールバックを設定することで、例外をそのまま不合格とせずに制御することも一応可能です。


バインディングソースのIDはInteger型なので、Integer型に変換できない文字列を与えるとSystem.FormatExceptionが発生し、検証は不合格となります。


不合格の場合、バインディングエンジンはValidationErrorオブジェクトを作成して、バインドされている要素のValidation.Errorsコレクションに追加します。そして、UI上で不合格に関するフィードバックを提供するために、Validation.ErrorTemplate添付プロパティに設定されたControlTemplateの内容が表示されます。既定のErrorTemplateは要素の周囲に赤い枠線が表示されるものとなっているため、上記のような結果となります。


なお、WPF 3.5以降では下記のようにBinding.ValidatesOnExceptionsプロパティをTrueに設定することで、ExceptionValidationRuleをValidationRulesコレクションに設定したのと同じ動作となります。


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">
    <Viewbox>
        <StackPanel Height="100" Width="100">
 
            <TextBox Margin="10" Text="{Binding ID, ValidatesOnExceptions=True}"/>
 
            <Button Margin="10" Content="Focus to me."/>
        </StackPanel>
    </Viewbox>
</Window>


その1はこれでおしまいです。基本の動作はこれで抑えたことになりますが、入力データ検証にはたくさんの方法が用意されています。その2ではその1で紹介できなかった要素について触れたいと思います。