Silverlight: Как вы реализуете проверку в пользовательских элементах управления?

#silverlight

#silverlight

Вопрос:

Как вы реализуете проверку в пользовательских элементах управления? Я хочу воспроизвести стандартную логику проверки, которую вы могли бы видеть, с помощью текстового поля, привязанного к данным модели или view-model, которое предоставляет IDataErrorInfo или INotifyDataErrorInfo.

Комментарии:

1. Что именно вы хотите изменить? Насколько я знаю, проверка является свойством привязок, и при сбое привязки возникает событие BindingValidationError. Нет разницы между стандартным элементом управления и пользовательским элементом управления.

2. Ошибка BindingValidationError: автор элемента управления обычно не должен ни вызывать, ни обрабатывать это событие при разработке элемента управления и реализации класса управления.

3. Представьте, что вы пишете свое собственное текстовое поле с нуля. Как бы вы реализовали такие вещи, как всплывающая подсказка по проверке?

Ответ №1:

Для реализации проверки вам следует добавить группу «ValidationStates» в VisualStateManager элемента управления.

Я проиллюстрирую простой пользовательский элемент управления TestControl с TestProperty помощью свойства.

Стиль в Generic.xaml в зависимости от состояния отображает синий текст или красную рамку с первым сообщением об ошибке:

 <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>
  

Существует 3 состояния:

  • Допустимо — ошибок проверки нет.
  • InvalidFocused — применяется, когда вы устанавливаете фокус на элемент управления в недопустимом состоянии. Элементы управления по умолчанию отображают красное всплывающее окно, а также красную рамку в этом состоянии, но в моем конкретном примере я не показываю это для простоты. Пользователи могут вызвать это состояние с помощью кнопки Tab на клавиатуре или щелчком по фокусируемому внутреннему элементу управления, такому как TextBox.
  • InvalidUnfocused — применяется, когда элемент управления находится в недопустимом состоянии, но не сфокусирован.

Вот код элемента управления, он содержит только одно свойство:

 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));
}
  

После этого, если вы используете IDataErrorInfo, правильный xaml будет:

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

Для INotifyDataErrorInfo правильный xaml еще проще:

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

Комментарии:

1. Спасибо, это имеет большой смысл. Вам было бы интересно написать полноценную статью о разработке пользовательских элементов управления в Silverlight?

2. @Jonathan Allen Что означает слово «проектирование»: реализация с нуля или оформление в Expression Blend? Я могу написать статью о пользовательских элементах управления в целом с точки зрения разработчика, но мои навыки дизайнера оставляют желать лучшего.

3. Что я ищу, так это шаги, необходимые для поддержки всех основных функциональных возможностей, таких как создание шаблонов, проверка и привязка данных. Уже есть бесчисленное количество статей о том, как сделать это красиво, как только это будет сделано. Напишите мне сообщение, и мы сможем обсудить детали: jonathan@infoq.com

4. @Jonathan Allen Я пытался написать статью о создании пользовательских элементов управления с нуля: vortexwolf.wordpress.com/2011/04/14 /… .

5. @imdadhusen Реализуйте интерфейс INotifyDataErrorInfo или IDataErrorInfo в вашей модели представления. Вы можете загрузить образец приложения из сообщения в моем блоге: vortexwolf.wordpress.com/2011/10/01 /…