WPF验证整个表单

时间:2008-09-19 18:54:18

标签: wpf validation

我对WPF验证系统感到非常失望。无论如何!如何通过单击“按钮”验证完整表单?

出于某种原因,WPF中的所有东西都太复杂了!我可以在ASP.NET中的一行代码中进行验证,这需要在WPF中使用10-20行代码!

我可以使用自己的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! 
}

5 个答案:

答案 0 :(得分:26)

如果输入的数据无效,WPF应用程序应禁用提交表单的按钮。您可以通过在IDataErrorInfo =true上使用绑定在业务对象上实现ValidatesOnDataErrors接口来实现此目的。要在出现错误时自定义单个控件的外观,请设置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是错误控件周围的细红色边框。如果这不适合您的视觉概念,请查看CodeProject上的Validation in Windows Presentation Foundation文章,深入了解可以采取哪些措施。

要使窗口真正起作用,窗口和客户中必须有一些基础结构。

代码背后

// 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,而不是业务对象。

虽然这确实比您提供的简单示例更多的代码,但它还具有比仅检查有效性更多的功能。这为用户提供了有关验证问题的细粒度和自动更新的指示,并且只要用户尝试输入无效数据,就会自动禁用“保存”按钮。

答案 1 :(得分:2)

我建议您查看业务对象上的IDataErrorInfo接口。另请查看这篇文章:Self Validating Text Box

答案 2 :(得分:1)

您可能对 WPF Application Framework (WAF) BookLibrary 示例应用感兴趣。它显示了如何在WPF中使用验证以及如何在存在验证错误时控制“保存”按钮。

答案 3 :(得分:1)

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实现为附加属性,可以改进语法,并且可以查看它here

答案 4 :(得分:0)

您的问题描述对我来说有点模糊。我的意思是,我不确定你的困难是什么。 假设DataContext是某种具有表示客户实例的propetry的演示者或控制器,而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的Web开发人员,我发现在WPF中这样的大多数任务都非常容易。