Wpf ErrorProvider - 集成IDataErrorInfo、WPF和验证应用程序块 (VAB)






2.14/5 (5投票s)
一个与VAB和IDataErrorInfo集成的WPF验证控件。
引言
ErrorProvider
是一个WPF控件,它尝试集成WPF、IDataErrorInfo
接口和Microsoft的验证应用程序块的最佳功能。
背景
我先说清楚。这个控件更多的是一个具有启发性的控件,而不是一个创新的控件。我刚开始使用WPF时,就需要验证,而WPF并没有为此提供任何控件。在谷歌搜索后,我找到了指向 Windows Presentation Foundation 中的验证、Validizor - WPF 的验证控件 和 委托和业务对象 的链接。
这些文章中没有什么是我可以不同意的。特别是,我对验证控件的高级设计目标是从这篇 Paul Stovell 的文章中获得的。我将它们(原样照搬)再次列在下面(从该文章中借用)
- 业务对象在不尝试保存的情况下,也应该允许它处于无效状态。
- 规则不应该在属性设置器中实现。
- 除非绝对必要,否则不应该检查规则。
- 不应该使用异常,除非对象在未经验证的情况下尝试保存。
- 任何已违反的规则都应该可以从业务对象中检索。
由于.NET对IDataErrorInfo
的支持,我几乎肯定会使用它作为提供业务对象错误信息的来源。然而,ValidationRule
中使用的声明性验证方法一直很有吸引力。那时,我决定使用验证应用程序块来声明验证规则,并使用IDataErrorInfo
接口来验证这些规则。
在这里,我的方法与Paul Stovell的文章不同,因为他使用自定义的Rule类进行验证。一方面,它们要求我实现程序化的验证代码。另一方面,这种方法不是标准化的,所以我决定使用VAB代替。
最后,这个控件或多或少是 Paul Stovell 的控件和 Buzz Weetman 的控件的混合体,为它们增加了许多功能和灵活性。已经付出了相当大的努力,使控件像WinForms的ErrorProvider
一样易于使用(我相信,并且成功了)。你只需要在你的窗体上保留一个ErrorProvider
实例,就像在Windows Forms中一样。
使用代码
首先,我将解释业务对象部分。业务对象需要实现IDataErrorInfo
来提供错误信息,并实现INotifyPropertyChanged
来生成属性更改通知。库项目有一个BusinessObjectBase
抽象类,它实现了这两者,甚至提供了这两个接口所需的所有功能。
对于IDataErrorInfo
,它使用对象属性上的ValidationRule
s进行验证。规则可以定义为属性或在配置中,因为VAB两者都允许。对于你的自定义对象,你只需要从这个类派生,并在属性或配置中提供声明性规则。你不需要编写一行代码来实现这个接口,因为基类处理了一切。这可以从测试应用程序中的Customer对象得到验证。
至于INotifyPropertyChanged,你只需要在属性设置器中调用基类的受保护的OnPropertyChanged方法。示例文例如下:
<StringLengthValidator(1, 25,
Messagetemplate:="Address must be between 1 and 20 characters in length")> _
<ContainsCharactersValidator("a",
Messagetemplate:="Address Should contain character a")> _
Public Property address() As String
Get
Return (Me._address)
End Get
Set(ByVal value As String)
Me._address = value
Me.onPropertyChanged(New PropertyChangedEventArgs("address"))
End Set
End Property
你甚至可以在对象上使用<HasSelfValidation>
属性来进行高级验证,ErrorProvider
会识别它。
ErrorProvider控件
你基本上需要在你的窗口上放置一个控件实例,并将所有其他控件添加为其子控件。ErrorProvider
的高级设计源自 Paul Stovell 的ErrorProvider
,我建议你看看 这篇文章 以更好地理解它是如何工作的。
下面的文字是从Paul的文章改编而来的,因为它非常适合这里。
(在附加的示例代码中)我构建的ErrorProvider
继承自WPF的Decorator
类,这意味着你可以“在其中放入东西”。要使用它,你只需要这样做:
<validators:ErrorProvider>
<StackPanel>
<TextBox Text="{Binding Path=Name}" />
<TextBox Text="{Binding Path=Age}" />
</StackPanel>
</validators:ErrorProvider>
我的ErrorProvider
工作原理是遍历它内部的所有控件,查找它们属性上的任何数据绑定。当一个绑定属性的值发生变化时,它会检查其DataContext
是否实现了IDataErrorInfo
,如果实现了,它就会获取任何错误消息,并使用内置的静态Validation
类显示它们。这意味着你可以使用我上面显示的样式和控件模板,同时将所有验证逻辑保留在另一个类中。
在WPF中遍历控件层级是通过 LogicalTreeHelper
类完成的。代码本身有点长,不适合在这里发布,但包含在页面顶部的示例代码下载中。
使用WPF ErrorProvider
带来了许多好处:
- 你的XAML会更加简洁,因为你不需要为每个绑定添加
ValidationRule
列表。 - 所有的验证都可以由你的业务对象完成,而不是在UI层。这允许你在保持UI信息丰富的同时,获得对你的对象的出色封装。
- 你可以调用
ErrorProvider
上的Validate()
方法来强制验证,并检查控件是否有效,而无需逐个检查。 - 你可以使用
GetFirstInvalidElement()
方法在你的窗体上获取第一个有错误的控件,以便轻松地将焦点设置到它上面。例如,如果你的“保存”按钮被点击了,但你想显示它们仍然有错误,这会非常有用。
关注点
ErrorProvider属性
ErrorProvider
提供以下属性,可用于设置其默认行为:
DefaultErrorTemplate
- 应用于违反验证的控件的默认错误模板。DefaultRuleSet
- 用于执行验证的RuleSet。DefaultRuleSource
- 用于执行验证的默认规则源(属性、配置或两者兼有)。
附加属性
此外,ErrorProvider
还提供以下附加属性,可用于按控件覆盖验证行为:
CausesValidation
- 将其切换为False
将不会验证控件。默认值为True
。ErrorTemplate
- 为控件分配自定义ErrorTemplate
。RuleSet
- 为控件分配自定义RuleSet
。RuleSource
- 为控件分配自定义RuleSource
。BindingOverride
- 这是一个有趣的属性。它允许你对DataContext
的某个其他属性执行验证,而不是对控件绑定的属性执行验证。虽然这个想法源自 Buzz Weetman 的工作,但它得到了极大的增强。你可以将OverrideRelativeSource
设置为Self
(替代属性被评估为Binding
的子项),或PreviousData
(替代属性被评估为控件的DataContext的子项)。测试应用程序中提供了一个示例。IsObjectValidation
- 如果要验证整个对象而不是其属性,请将其设置为True
。你可以再次使用BindingOverride
来进一步自定义此设置。测试应用程序中提供了一个示例。
结论
这里没有一种万能的方法。但是,我相信我的ErrorProvider
可以适应大多数情况;-)
它采用标准化的方法,集成了WPF和IDataErrorInfo
的最佳功能(许多WPF和WinForms控件支持IDataErrorInfo
,从而允许你的业务对象直接与这些控件一起使用),以及VAB的企业级可扩展性。
致谢
正如文章中一直提到的,我研究了Paul和Buzz的工作,发现它们不适合我的场景,将两者结合并改进,然后突然决定在CodeProject上发布它,因为我亏欠它。我完全承认我从他们的工作中借鉴的功能和文章片段。