入力データ検証 その8 Silverlight 2
Silverlight 2の入力データ検証は、WPFの入力データ検証から大幅に機能が絞られたものとなっています(入力データ検証に限った話ではありませんが…)。
まず検証ルールについてですが、Silverlight 2のBindingクラスにはValidationRulesプロパティがありません。ではどうやってValidationRuleを適用させれば良いかといいますと、ValidatesOnExceptionsプロパティはありますので、これをTrueに設定してExceptionValidationRuleを設定した状態にします。ただし、ExceptionValidationRuleはSilverlight 2には存在しませんので、あくまで同じ動作となるということです。逆に言いますと、DataErrorValidationRuleやカスタムのValidationRuleといったこれ以外の検証ルールを適用することができません。
そしてUI上のフィードバック方法ですが、これはその4でご紹介したNotifyOnValidationErrorプロパティとそれによって発生するイベントを利用した方法だけが可能になっています。このイベントはWPFではValidation.Error添付イベントとして提供されていましたが、Silverlight 2ではFrameworkElement.BindingValidationErrorイベントとなっています。
Page.xaml
<UserControl x:Class="SilverlightValidationSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300" FontSize="32">
<StackPanel x:Name="LayoutRoot" Background="LightGray"
BindingValidationError="LayoutRoot_BindingValidationError">
<TextBox Margin="20"
Text="{Binding ID, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
<Button Margin="20" Content="Focus to me."/>
</StackPanel>
</UserControl>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300" FontSize="32">
<StackPanel x:Name="LayoutRoot" Background="LightGray"
BindingValidationError="LayoutRoot_BindingValidationError">
<TextBox Margin="20"
Text="{Binding ID, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"/>
<Button Margin="20" Content="Focus to me."/>
</StackPanel>
</UserControl>
Silverlightでは依存関係プロパティにおけるデフォルトのBindingのModeを指定することができないため、TextBoxのTextプロパティもデフォルトのModeはOneWayになります。そのため、WPFと異なり明示的にTwoWayと指定してやる必要があります。
Page.xaml.vb
Partial Public Class Page
Inherits UserControl
Public Sub New()
InitializeComponent()
Me.DataContext = New DataSource()
End Sub
Private Sub LayoutRoot_BindingValidationError(ByVal sender As System.Object, ByVal e As System.Windows.Controls.ValidationErrorEventArgs)
If e.Action = ValidationErrorEventAction.Added Then
CType(e.OriginalSource, TextBox).BorderBrush = New SolidColorBrush(Colors.Red)
CType(e.OriginalSource, TextBox).BorderThickness = New Thickness(3)
ToolTipService.SetToolTip(e.OriginalSource, e.Error.Exception.Message)
ElseIf e.Action = ValidationErrorEventAction.Removed Then
CType(e.OriginalSource, TextBox).ClearValue(BorderBrushProperty)
CType(e.OriginalSource, TextBox).ClearValue(BorderThicknessProperty)
ToolTipService.SetToolTip(e.OriginalSource, Nothing)
End If
e.Handled = True
End Sub
End Class
Inherits UserControl
Public Sub New()
InitializeComponent()
Me.DataContext = New DataSource()
End Sub
Private Sub LayoutRoot_BindingValidationError(ByVal sender As System.Object, ByVal e As System.Windows.Controls.ValidationErrorEventArgs)
If e.Action = ValidationErrorEventAction.Added Then
CType(e.OriginalSource, TextBox).BorderBrush = New SolidColorBrush(Colors.Red)
CType(e.OriginalSource, TextBox).BorderThickness = New Thickness(3)
ToolTipService.SetToolTip(e.OriginalSource, e.Error.Exception.Message)
ElseIf e.Action = ValidationErrorEventAction.Removed Then
CType(e.OriginalSource, TextBox).ClearValue(BorderBrushProperty)
CType(e.OriginalSource, TextBox).ClearValue(BorderThicknessProperty)
ToolTipService.SetToolTip(e.OriginalSource, Nothing)
End If
e.Handled = True
End Sub
End Class
BorderBrushプロパティとBorderThicknessプロパティは、検証が合格した場合にDependencyObject.ClearValueメソッドを使って設定された値を消去しているところがポイントです。こうしておけば、たとえStyleなどで値が変更されていたとしても期待する最初の状態に戻るという動作が実現できます。
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
検証ロジックを書く場合には、下記のようにExceptionを投げることになります。
DataSource.vb
Public Class DataSource
Dim _id As Integer
Public Property ID() As Integer
Get
ID = _id
End Get
Set(ByVal value As Integer)
If value <= 0 Then
Throw New Exception("IDは0より大きな値を入力してください")
End If
_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)
If value <= 0 Then
Throw New Exception("IDは0より大きな値を入力してください")
End If
_id = value
End Set
End Property
End Class
Exceptionですので、[デバッグなしで実行]でないと動作を確認できませんのでご注意ください。
これで8回続いた入力データ検証シリーズは終了です。また何かシリーズものができたら書いてみたいと思います。