Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Silverlight: How do you implement validation in custom controls?

Tags:

silverlight

How do you implement validation in custom controls? I am looking to replicate the standard validation logic you would see with a TextBox data-bound to a model or view-model that exposes IDataErrorInfo or INotifyDataErrorInfo.

like image 755
Jonathan Allen Avatar asked Apr 07 '11 21:04

Jonathan Allen


1 Answers

To implement validation you should add the "ValidationStates" group to the VisualStateManager of the control.

I will illustrate the simple custom control TestControl with the TestProperty property.

Style in the Generic.xaml, depending on the state displays the blue text or the red border with the first error message:

<Style TargetType="local:TestControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:TestControl">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="ValidationStates">
                            <VisualState x:Name="Valid" />
                            <VisualState x:Name="InvalidFocused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="InvalidBorder" Storyboard.TargetProperty="Visibility" Duration="0">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="InvalidUnfocused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="InvalidBorder" Storyboard.TargetProperty="Visibility" Duration="0">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>    
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <TextBlock Text="{TemplateBinding TestProperty}" Foreground="Blue" />
                    <Border x:Name="InvalidBorder"  BorderBrush="Red" BorderThickness="2" Visibility="Collapsed">
                        <TextBlock Text="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource TemplatedParent}}" Foreground="Red" FontWeight="Bold" />
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

There are 3 states:

  • Valid - No validation errors.
  • InvalidFocused - Applied when you set the focus to the control in the invalid state. Default controls display the red popup as well as the red border in this state, but in my particular example I don't display it for simplicity. Users can invoke this state by using the Tab keyboard button or by clicking a focusable inner control like TextBox.
  • InvalidUnfocused - Applied when the control in the invalid state but isn't focused.

Here is the code of the control, it contains only one property:

public class TestControl : Control
{
    public TestControl()
    {
        this.DefaultStyleKey = typeof(TestControl);
    }

    public string TestProperty
    {
        get { return (string)GetValue(TestPropertyProperty); }
        set { SetValue(TestPropertyProperty, value); }
    }

    public static readonly DependencyProperty TestPropertyProperty =
        DependencyProperty.Register("TestProperty", typeof(string), typeof(TestControl), new PropertyMetadata(null));
}

After that if you use the IDataErrorInfo, the correct xaml is:

<local:TestControl TestProperty="{Binding SomeModelProperty, ValidatesOnDataErrors=True}" />

For the INotifyDataErrorInfo, the correct xaml is even simplier:

<local:TestControl TestProperty="{Binding SomeModelProperty}" />
like image 97
vortexwolf Avatar answered Oct 13 '22 23:10

vortexwolf