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

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

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

Я могу сделать это, используя мою собственную Framework 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! 
}

Ответ 1

Приложение WPF должно отключить кнопку для отправки формы, если введенные данные недействительны. Вы можете добиться этого, реализовав IDataErrorInfo интерфейс на своем бизнес-объекте, используя Bindings с 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 с двумя TextBox es, где вы можете редактировать имя и фамилию клиента. Кнопка "Сохранить" активируется только в том случае, если ошибки проверки не произошли. TextBlock под кнопкой отображаются текущие ошибки, поэтому пользователь знает, что происходит.

По умолчанию ErrorTemplate - тонкая красная рамка вокруг ошибочного элемента управления. Если это не вписывается в визуальную концепцию, посмотрите Validation in 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, но не от бизнес-объекта.

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

Ответ 2

Я бы предложил посмотреть интерфейс IDataErrorInfo на вашем бизнес-объекте. Также ознакомьтесь с этой статьей: Self Validating Text Box

Ответ 3

Вам может быть интересно приложение BookLibrary приложения WPF Application Framework (WAF). Он показывает, как использовать проверку в WPF и как управлять кнопкой "Сохранить", когда существуют ошибки проверки.

Ответ 4

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

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

<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 в качестве прикрепленного свойства, синтаксис может быть улучшен, и вы можете взглянуть на него здесь

Ответ 5

Описание вашей проблемы немного расплывчато для меня. Я имею в виду, я не совсем уверен, какова твоя трудность. Предполагая, что 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.