65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.14/5 (5投票s)

2008年9月23日

CPOL

6分钟阅读

viewsIcon

65223

downloadIcon

2785

一个与VAB和IDataErrorInfo集成的WPF验证控件。

Screenshot

引言

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,它使用对象属性上的ValidationRules进行验证。规则可以定义为属性或在配置中,因为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 StovellErrorProvider,我建议你看看 这篇文章 以更好地理解它是如何工作的。

下面的文字是从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上发布它,因为我亏欠它。我完全承认我从他们的工作中借鉴的功能和文章片段。

© . All rights reserved.