整个表单的 WPF 验证
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/104520/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Validation for the whole form
提问by azamsharp
I have been seriously disappointed with WPF validation system. Anyway! How can I validate the complete form by clicking the "button"?
我对 WPF 验证系统非常失望。反正!如何通过单击“按钮”来验证完整的表单?
For some reason everything in WPF is soo complicated! I can do the validation in 1 line of code in ASP.NET which requires like 10-20 lines of code in WPF!!
出于某种原因,WPF 中的一切都太复杂了!我可以在 ASP.NET 中用 1 行代码进行验证,而在 WPF 中需要 10-20 行代码!!
I can do this using my own ValidationEngine 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!
}
回答by David Schmitt
A WPF application should disable the button to submit a form iff the entered data is not valid. You can achieve this by implementing the IDataErrorInfointerface on your business object, using Bindings with ValidatesOnDataErrors
=true
. For customizing the look of individual controls in the case of errors, set a Validation.ErrorTemplate
.
如果输入的数据无效,WPF 应用程序应禁用提交表单的按钮。您可以通过在业务对象上实现IDataErrorInfo接口来实现这一点,使用 Bindings with 。要在出现错误时自定义单个控件的外观,请设置.ValidatesOnDataErrors
=true
Validation.ErrorTemplate
XAML:
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>
This creates a Window
with two TextBox
es where you can edit the first and last name of a customer. The "Save" button is only enabled if no validation errors have occurred. The TextBlock
beneath the button shows the current errors, so the user knows what's up.
这将创建一个Window
带有两个TextBox
es 的 es,您可以在其中编辑客户的名字和姓氏。“保存”按钮仅在未发生验证错误时启用。该TextBlock
按钮的下方显示当前的错误,这样用户就知道这是怎么回事。
The default ErrorTemplate
is a thin red border around the erroneous Control. If that doesn't fit into you visual concept, look at Validation in Windows Presentation Foundationarticle on CodeProject for an in-depth look into what can be done about that.
默认值ErrorTemplate
是错误控件周围的红色细边框。如果这不符合您的视觉概念,请查看CodeProject 上的Windows Presentation Foundation文章中的验证,以深入了解可以对此做些什么。
To get the window to actually work, there has to be a bit infrastructure in the Window and the Customer.
为了让窗口真正工作,窗口和客户中必须有一些基础设施。
Code Behind
背后的代码
// 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]; }
}
}
An obvious improvement would be to move the IDataErrorInfo
implementation up the class hierarchy, since it only depends on the ValidationEngine
, but not the business object.
一个明显的改进是将IDataErrorInfo
实现向上移动到类层次结构,因为它只依赖于ValidationEngine
,而不依赖于业务对象。
While this is indeed more code than the simple example you provided, it also has quite a bit more of functionality than only checking for validity. This gives you fine grained, and automatically updated indications to the user about validation problems and automatically disables the "Save" button as long as the user tries to enter invalid data.
虽然这确实比您提供的简单示例代码更多,但它也具有比仅检查有效性更多的功能。这为您提供了有关验证问题的细粒度且自动更新的指示,并在用户尝试输入无效数据时自动禁用“保存”按钮。
回答by adriaanp
I would suggest to look at the IDataErrorInfo interface on your business object. Also have a look at this article: Self Validating Text Box
我建议查看您的业务对象上的 IDataErrorInfo 接口。另请查看这篇文章:自验证文本框
回答by jbe
You might be interested in the BookLibrarysample application of the WPF Application Framework (WAF). It shows how to use validation in WPF and how to control the Save button when validation errors exists.
您可能对WPF 应用程序框架 (WAF)的BookLibrary示例应用程序感兴趣。它展示了如何在 WPF 中使用验证以及如何在存在验证错误时控制“保存”按钮。
回答by skjagini
ValidatesOnDataError is used to validate business rules against your view models, and it will validate only if the binding succeeds.
ValidatesOnDataError 用于根据您的视图模型验证业务规则,并且只有在绑定成功时才会验证。
ValidatesOnExceptions needs to be applied along with ValidatesOnDataError to handle those scenarios where wpf cannot perform binding because of data type mismatch, lets say you want to bind a TextBox to the Age (integer) property in your view model
ValidatesOnExceptions 需要与 ValidatesOnDataError 一起应用,以处理 wpf 由于数据类型不匹配而无法执行绑定的情况,假设您想将 TextBox 绑定到视图模型中的 Age(整数)属性
<TextBox Text="{Binding Age, ValidatesOnDataErrors=true, UpdateSourceTrigger=PropertyChanged}" />
If the user enters invalid entry by typing alphabets rather than numbers as age, say xyz, the wpf databinding will silently ignores the value as it cannot bind xyz to Age, and the binding error will be lost unless the binding is decorated with ValidatesOnExceptions
如果用户通过键入字母而不是数字作为年龄输入无效条目,例如 xyz,wpf 数据绑定将默默地忽略该值,因为它无法将 xyz 绑定到年龄,并且绑定错误将丢失,除非绑定使用ValidatesOnExceptions修饰
<TextBox Text="{Binding Age, ValidatesOnDataErrors=true, ValidatesOnExceptions="True", UpdateSourceTrigger=PropertyChanged}" />
ValidatesOnException uses default exception handling for binding errors using ExceptionValidationRule, the above syntax is a short form for the following
ValidatesOnException 使用 ExceptionValidationRule 对绑定错误使用默认异常处理,上述语法是以下的简短形式
<TextBox>
<TextBox.Text>
<Binding Path="Age" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
You can defined your own rules to validate against the user input by deriving from ValidationRule and implementing Validate method, NumericRule in the following example
您可以定义自己的规则,通过从 ValidationRule 派生并在以下示例中实现 Validate 方法 NumericRule 来验证用户输入
<TextBox.Text>
<Binding Path="Age" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<rules:NumericRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
The validation rules should be generic and not tied to business, as the later is accomplished through IDataErrorInfo and ValidatesOnDataError.
验证规则应该是通用的,不与业务绑定,因为后者是通过 IDataErrorInfo 和 ValidatesOnDataError 完成的。
The above syntax is quite messy compared to the one line binding syntax we have, by implementing the ValidationRule as an attached property the syntax can be improved and you can take a look at it here
与我们拥有的单行绑定语法相比,上述语法相当混乱,通过将 ValidationRule 实现为附加属性,可以改进语法,您可以在此处查看
回答by Christopher Bennage
The description of your problem is a little vague to me. I mean, I'm not exactly sure what your difficulty is. Assuming that the DataContext is some sort of presenter or controller that has a propetry representing the customer instance, and ValidateCommand is a property of type ICommand:
你的问题的描述对我来说有点模糊。我的意思是,我不确定你的困难是什么。假设 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>
This XAML is really simplified, of course, and there are other ways to do it. As a Web developer who is now heavily involved with WPF, I find most tasks like this significantly easier in WPF.
当然,这个 XAML 确实简化了,还有其他方法可以做到。作为一名现在大量参与 WPF 的 Web 开发人员,我发现 WPF 中的大多数此类任务都变得更加容易。