15

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

出于某种原因,WPF 中的一切都太复杂了!我可以在 ASP.NET 中的 1 行代码中进行验证,这需要 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! 
}
4

5 回答 5

27

如果输入的数据无效,WPF 应用程序应禁用提交表单的按钮。您可以通过在业务对象上实现IDataErrorInfo接口来实现这一点,使用 Bindings with . 要在出现错误时自定义各个控件的外观,请设置一个.ValidatesOnDataErrors=trueValidation.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 的 es,您可以在其中编辑客户的名字和姓氏。只有在没有发生验证错误时才启用“保存”按钮。按钮下方TextBlock显示当前错误,因此用户知道发生了什么。

默认值ErrorTemplate是错误控件周围的细红色边框。如果这不符合您的视觉概念,请查看CodeProject 上的 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,而不依赖于业务对象。

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

于 2008-10-08T11:50:38.813 回答
2

我建议查看您的业务对象上的 IDataErrorInfo 接口。也看看这篇文章:自我验证文本框

于 2008-09-19T19:49:41.953 回答
1

您可能对WPF 应用程序框架 (WAF)的BookLibrary示例应用程序感兴趣。它展示了如何在 WPF 中使用验证,以及在存在验证错误时如何控制“保存”按钮。

于 2010-08-16T17:16:46.273 回答
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 实现为附加属性,可以改进语法,您可以在这里查看

于 2010-11-24T05:34:08.370 回答
0

你的问题的描述对我来说有点模糊。我的意思是,我不确定你的困难是什么。假设 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 的 Web 开发人员,我发现大多数类似的任务在 WPF 中都变得容易得多。

于 2008-10-01T13:45:57.083 回答