整个表格的WPF验证

时间:2020-03-06 14:27:21  来源:igfitidea点击:

我对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! 
}

解决方案

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

对问题的描述对我来说有点模糊。我的意思是,我不确定困难是什么。
假设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中,大多数这样的任务都非常容易。

如果输入的数据无效,则WPF应用程序应禁用该按钮以提交表单。我们可以通过使用带有ValidatesOnDataErrors = true的绑定在业务对象上实现IDataErrorInfo接口来实现此目的。为了在出现错误的情况下自定义单个控件的外观,请设置" 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>

这将创建一个带有两个TextBox的Window,我们可以在其中编辑客户的名字和姓氏。仅当未发生验证错误时才启用"保存"按钮。按钮下方的" TextBlock"显示当前错误,因此用户知道发生了什么。

默认的" ErrorTemplate"是错误控件周围的红色细边框。如果这不适合视觉概念,请查看CodeProject上Windows Presentation Foundation中的Validation,以深入了解该怎么做。

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

背后的代码

// 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",而不依赖于业务对象。

尽管确实比我们提供的简单示例更多的代码,但它还具有比仅检查有效性更多的功能。这为我们提供了细粒度的信息,并会自动向用户提供有关验证问题的指示,并在用户尝试输入无效数据时自动禁用"保存"按钮。

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

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实现为添加属性,可以改进语法,我们可以在此处进行查看