入力データの検証 その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
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>
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
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>
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で紹介できなかった要素について触れたいと思います。