入力データ検証 その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>


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


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


検証ロジックを書く場合には、下記のように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


Exceptionですので、[デバッグなしで実行]でないと動作を確認できませんのでご注意ください。





これで8回続いた入力データ検証シリーズは終了です。また何かシリーズものができたら書いてみたいと思います。