我对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!
}
答案 0 :(得分:26)
如果输入的数据无效,WPF应用程序应禁用提交表单的按钮。您可以通过在IDataErrorInfo =true
上使用绑定在业务对象上实现ValidatesOnDataErrors
接口来实现此目的。要在出现错误时自定义单个控件的外观,请设置Validation.ErrorTemplate
。
<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中这样的大多数任务都非常容易。