Проверка WPF для всей формы

Я был серьезно разочарован системой проверки WPF. Так или иначе! Как я могу проверить заполненную форму, нажав «кнопку»?

Почему-то в WPF все так сложно! Я могу выполнить проверку в 1 строке кода в ASP.NET, что требует 10-20 строк кода в WPF!!

Я могу сделать это, используя собственную структуру ValidationEngine:

Customer customer = new Customer();
customer.FirstName = "John";
customer.LastName = String.Empty;

ValidationEngine.Validate(customer);

if (customer.BrokenRules.Count > 0)
{
   // do something display the broken rules! 
}

person azamsharp    schedule 19.09.2008    source источник


Ответы (5)


Приложение WPF должно отключить кнопку для отправки формы, если введенные данные недействительны. Этого можно добиться путем реализации интерфейса IDataErrorInfo на вашем бизнес-объект с использованием привязок с ValidatesOnDataErrors =true. Для настройки внешнего вида отдельных элементов управления в случае ошибок установите Validation.ErrorTemplate.

XAML:

<Window x:Class="Example.CustomerWindow" ...>
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Save"
                        CanExecute="SaveCanExecute"
                        Executed="SaveExecuted" />
    </Window.CommandBindings>
    <StackPanel>
        <TextBox Text="{Binding FirstName, ValidatesOnDataErrors=true, UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Text="{Binding LastName, ValidatesOnDataErrors=true, UpdateSourceTrigger=PropertyChanged}" />
        <Button Command="ApplicationCommands.Save" IsDefault="True">Save</Button>
        <TextBlock Text="{Binding Error}"/>
    </StackPanel>
</Window>

Это создает Window с двумя TextBoxes, где вы можете редактировать имя и фамилию клиента. Кнопка «Сохранить» доступна только в том случае, если ошибок проверки не произошло. TextBlock под кнопкой показывает текущие ошибки, поэтому пользователь знает, что случилось.

По умолчанию ErrorTemplate представляет собой тонкую красную рамку вокруг ошибочного элемента управления. Если это не вписывается в вашу визуальную концепцию, посмотрите Проверка в Windows Presentation Foundation статья о CodeProject для более подробного изучения того, что можно с этим сделать.

Чтобы окно действительно работало, в окне и клиенте должна быть небольшая инфраструктура.

Код позади

// The CustomerWindow class receives the Customer to display
// and manages the Save command
public class CustomerWindow : Window
{
    private Customer CurrentCustomer;
    public CustomerWindow(Customer c) 
    {
        // store the customer for the bindings
        DataContext = CurrentCustomer = c;
        InitializeComponent();
    }

    private void SaveCanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = ValidationEngine.Validate(CurrentCustomer);
    }

    private void SaveExecuted(object sender, ExecutedRoutedEventArgs e) 
    {
        CurrentCustomer.Save();
    }
}

public class Customer : IDataErrorInfo, INotifyPropertyChanged
{
    // holds the actual value of FirstName
    private string FirstNameBackingStore;
    // the accessor for FirstName. Only accepts valid values.
    public string FirstName {
        get { return FirstNameBackingStore; }
        set {
            FirstNameBackingStore = value;
            ValidationEngine.Validate(this);
            OnPropertyChanged("FirstName");
        }
    }
    // similar for LastName        

    string IDataErrorInfo.Error {
        get { return String.Join("\n", BrokenRules.Values); }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get { return BrokenRules[columnName]; }
    }
}

Очевидным улучшением было бы перемещение реализации IDataErrorInfo вверх по иерархии классов, поскольку она зависит только от ValidationEngine, но не от бизнес-объекта.

Хотя это действительно больше кода, чем простой пример, который вы предоставили, он также имеет немного больше функциональных возможностей, чем просто проверка на достоверность. Это дает вам подробные и автоматически обновляемые указания пользователю о проблемах проверки и автоматически отключает кнопку «Сохранить», пока пользователь пытается ввести неверные данные.

person David Schmitt    schedule 08.10.2008
comment
Это кажется слишком много, когда все, что мне нужно, это убедиться, что все поля заполнены. - person azamsharp; 16.10.2008
comment
Если вам нужно только убедиться, что все поля заполнены, вы можете просто поместить свои коды проверки в обработчик Click кнопки отправки. Но тогда ваши пользователи спросят, почему я не могу отправить форму? и вам все равно придется реализовать все уведомления и прочее. - person David Schmitt; 16.10.2008
comment
Было бы логично, если бы все это было частью TextBox или элементов управления вводом. Как ‹TextBox RequiredInput=true ErrorMessage=Пожалуйста, заполните поля /› - person azamsharp; 17.10.2008
comment
Правила проверки являются частью модели данных, а не графического интерфейса. Нужно иметь возможность проверить достоверность объекта без графического интерфейса. Например, подумайте о пакетно-ориентированных процессорах данных. - person David Schmitt; 17.10.2008
comment
Это моя точка зрения! Проверка должна выполняться на уровне графического интерфейса, а затем на уровне домена. - person azamsharp; 17.10.2008
comment
Это моя точка зрения! WPF может делегировать проверку на уровень домена, используя привязку и настройку ValidatesOnDataErrors=true и/или ValidatesOnException=true. Мой ответ показывает один из способов сделать это. - person David Schmitt; 17.10.2008

Я бы посоветовал взглянуть на интерфейс IDataErrorInfo вашего бизнес-объекта. Также ознакомьтесь с этой статьей: Текстовое поле с самопроверкой

person adriaanp    schedule 19.09.2008


ValidatesOnDataError используется для проверки бизнес-правил в отношении ваших моделей представления и будет проверяться только в случае успешного выполнения привязки.

ValidatesOnExceptions необходимо применять вместе с ValidatesOnDataError для обработки тех сценариев, где wpf не может выполнить привязку из-за несоответствия типа данных, скажем, вы хотите привязать TextBox к свойству Age (целое число) в вашей модели представления

<TextBox Text="{Binding Age, ValidatesOnDataErrors=true, UpdateSourceTrigger=PropertyChanged}" />

Если пользователь вводит недопустимую запись, вводя алфавиты, а не цифры в качестве возраста, скажем, xyz, привязка данных wpf молча игнорирует значение, поскольку не может привязать xyz к Age, и ошибка привязки будет потеряна, если привязка не украшена ValidatesOnExceptions

<TextBox Text="{Binding Age, ValidatesOnDataErrors=true, ValidatesOnExceptions="True", UpdateSourceTrigger=PropertyChanged}" />

ValidatesOnException использует обработку исключений по умолчанию для ошибок привязки с помощью ExceptionValidationRule, приведенный выше синтаксис представляет собой краткую форму для следующего

<TextBox>
    <TextBox.Text>
        <Binding Path="Age" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
            <Binding.ValidationRules>
                  <ExceptionValidationRule />
             </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Вы можете определить свои собственные правила для проверки ввода пользователя, производные от ValidationRule и реализовав метод Validate, NumericRule в следующем примере.

<TextBox.Text>
 <Binding Path="Age" ValidatesOnDataErrors="True">
   <Binding.ValidationRules>
        <rules:NumericRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>

Правила проверки должны быть общими и не привязанными к бизнесу, поскольку последнее выполняется с помощью IDataErrorInfo и ValidatesOnDataError.

Приведенный выше синтаксис довольно запутан по сравнению с синтаксисом привязки одной строки, который у нас есть, путем реализации ValidationRule в качестве прикрепленного свойства синтаксис можно улучшить, и вы можете взглянуть на него здесь

person skjagini    schedule 24.11.2010

Описание вашей проблемы для меня немного расплывчато. Я имею в виду, я не совсем уверен, в чем твоя трудность. Предполагая, что DataContext является своего рода презентатором или контроллером, у которого есть свойство, представляющее экземпляр клиента, а ValidateCommand является свойством типа ICommand:

  <StackPanel>  
    <TextBox Text="{Binding CurrentCustomer.FirstName}" />
    <TextBox Text="{Binding CurrentCustomer.LastName}" />
    <Button Content="Validate" 
            Command="{Binding ValidateCommand}"
            CommandParameter="{Binding CurrentCustomer}" />
    <ItemsControl ItemsSource="{Binding CurrentCustomer.BrokenRules}" />
  </StackPanel>

Этот XAML, конечно, очень упрощен, и есть другие способы сделать это. Как веб-разработчик, активно работающий с WPF, я считаю, что большинство подобных задач значительно проще в WPF.

person Christopher Bennage    schedule 01.10.2008