воскресенье, 13 июля 2014 г.

Простая валидация в WPF

Очень простой пример отображения ошибок валидации рядом с контроллерами(в этом примереTextBox) в WPF
Введение
Это простой пример валидации в XAML для WPF элементов управления (далее элемента управления или ЕУ) и отображение сообщений об ошибках.

Предыстория

Я искал что-то не из коробки WPF где не надо дополнительно кодировать стили или ну нужен шаблон для отображения ошибок валидации, где нам нужен только написать логику валидации для каждого ЕУ и она должна автоматический показывать иконку ошибки или сообщение рядом с ЕУ.

Как бы то ни было, я не смог найти проще для WPF чем описываемый в данной статье метод.
Но данная задача может быть достигнуто двумя простыми шагами.
Используемый код
Ниже приведена очень простая форма в XAML в которой создано 3 textbox:
Добавим код так что когда значения вводятся текстовых полях, они автоматический запускают валидацию и если будут ошибки, они будут отображаться рядом с соответствующим ЕУ. Для того что бы сделать это, необходимо сделать следующие 2 шага:
  1. Создать ControlTemplate с AdornedElementPlaceHolder
  2. Подключить или создать класс валидации дочерний от абстрактного класса ValidationRule
Ниже представлен простой шаблон валидации ЕУ. Давайте начнем с простого шаблона валидации ЕУ все что нам нужно это TextBlock который будет отображать красный восклицательный знак рядом с ЕУ не прошел верификацию.
<ControlTemplate x:Key="validationErrorTemplate">
    <DockPanel>
        <TextBlock Foreground="Red" 
            DockPanel.Dock="Top">!</TextBlock>
        <AdornedElementPlaceholder 
           x:Name="ErrorAdorner"
        ></AdornedElementPlaceholder>
    </DockPanel>
</ControlTemplate> 
Давайте создадим еще класс валидации дочерний от абстрактного класса ValidationRule и реализуем его как показано ниже.
public class NameValidator : ValidationRule
{
    public override ValidationResult Validate
      (object value, System.Globalization.CultureInfo cultureInfo)
    {
        if (value == null)
            return new ValidationResult(false, "value cannot be empty.");
        else
        {
            if (value.ToString().Length > 3)
                return new ValidationResult
                (false, "Name cannot be more than 3 characters long.");
        }
        return ValidationResult.ValidResult;
    }
}
Давайте подключим этот шаблон валидации ЕУ и правило валидации к ЕУ который мы хотим проверить.
<TextBox Height="23" HorizontalAlignment="Left" 
              Grid.Column="1" Grid.Row="0" Name="textBox1" 
              VerticalAlignment="Top" Width="120" 
              Validation.ErrorTemplate="{StaticResource validationErrorTemplate}"
         >
    <TextBox.Text>
        <Binding Path="Name" Mode="TwoWay" 
        UpdateSourceTrigger="LostFocus">
            <Binding.ValidationRules>
                <local:NameValidator></local:NameValidator>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox> 
Когда мы запустим приложение в введем имя длиннее трех символов, отобразится красный восклицательный знак обозначающий ошибку при проверке.

Сейчас давайте заменим TextBlock в упомянутом выше соде шаблона валидации ЕУ (в строке которая отображается жирным шрифтом) на StackPanel ellipse и TextBlock для отображения ошибок валидации. Пример указан ниже:
<ControlTemplate x:Key="validationErrorTemplate">
    <DockPanel>
    <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
        <Grid Width="12" Height="12">
            <Ellipse Width="12" Height="12" 
            Fill="Red" HorizontalAlignment="Center" 
            VerticalAlignment="Center"
                     
                     ></Ellipse>
            <TextBlock Foreground="White" FontWeight="Heavy" 
            FontSize="8" HorizontalAlignment="Center" 
            VerticalAlignment="Center" TextAlignment="Center"
                       ToolTip="{Binding ElementName=ErrorAdorner, 
                       Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
                       >X</TextBlock>
        </Grid>
        <TextBlock Foreground="Red" FontWeight="12" Margin="2,0,0,0" 
                   Text="{Binding ElementName=ErrorAdorner, 
                   Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
                   ></TextBlock>                    
        </StackPanel>
        <AdornedElementPlaceholder 
        x:Name="ErrorAdorner" ></AdornedElementPlaceholder>
    </DockPanel>
</ControlTemplate>
Теперь когда запустим наш код и валидация выдаст ошибку, Ошибки валидации будут отображены как показано на скриншоте ниже (таким же образом напишите класс валидации для age и phone ).
Это все что нужно для простого отображения ошибок валидации ЕУ. Обратите внимание, в шаблоне элемента управления проверки, мы используем DockPanel в качестве контроля макета, поэтому мы можем легко изменить, где будет отображаться значок ошибки и сообщение об ошибке. Мы можем показать их на верхней части элемента управления, который не прошел валидацию (как на картинке выше), или слева, справа или нижней.

Подводные камни

Имеются подводные камни о которых автор оригинальной статьи забыл упомянуть.
Дальнейшие строки будут меняться (это пока заметка для меня что бы не забыл с чего продолжить компать)
Первое автор не помянул про подключаемое пространство имен System.ComponentModel и про то что класс нашего окна получает еще интерфейс INotifyPropertyChanged
public partial class MainWindow : Window, INotifyPropertyChanged
В конструкторе добавлено следующее:
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }
также добавлен следующий код в классе:

        public string Name { get; set; }
        public int Age { get; set; }
        public string Phone { get; set; }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)        {
            if (!Validation.GetHasError(textBox1) && !Validation.GetHasError(textBox2) && !Validation.GetHasError(textBox3))            {                // do the proicessing            }        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string property)        {            if (PropertyChanged != null)                PropertyChanged(this, new PropertyChangedEventArgs(property));        }
Ссылка на оригинал статьи

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

Отправить комментарий