【发布时间】:2010-11-10 12:27:04
【问题描述】:
MSDN Magazine 上有一篇关于 MVVM 的好文章,他们将 Xaml 中的验证错误绑定到 Validation.ErrorTemplate="{x:Null}"。我不明白为什么以及如何从 IDataErrorInfo 显示错误?任何人都可以告诉我如何使用 MVVM 方法将错误消息显示到屏幕上?
【问题讨论】:
MSDN Magazine 上有一篇关于 MVVM 的好文章,他们将 Xaml 中的验证错误绑定到 Validation.ErrorTemplate="{x:Null}"。我不明白为什么以及如何从 IDataErrorInfo 显示错误?任何人都可以告诉我如何使用 MVVM 方法将错误消息显示到屏幕上?
【问题讨论】:
当您绑定到支持 IDataErrorInfo 的对象时,需要考虑 WPF Binding 类的几个特性:
ValidatesOnDataErrors 必须为 True。这指示 WPF 在底层对象上查找并使用 IDataError 接口。
如果源对象的 IDataError 接口报告了验证问题,附加属性 Validation.HasError 将在目标对象上设置为 true。然后,您可以将此属性与触发器一起使用来更改控件的工具提示以显示验证错误消息(我在当前项目中这样做并且最终用户喜欢它)。
Validation.Errors 附加属性将包含上次验证尝试导致的任何 ValidationResult 错误的枚举。如果您使用工具提示方法,请使用 IValueConverter 仅检索第一项...否则您会遇到绑定错误以显示错误消息本身。
绑定类公开了 NotifyOnValidationError,当它为 True 时,每次验证规则的状态发生变化时,都会导致路由事件从绑定控件中冒泡。如果您想在绑定控件的容器中实现事件处理程序,然后将验证消息添加到列表框或从列表框移除验证消息,这将非常有用。
MSDN 上提供了两种反馈样式(工具提示和列表框)的示例,但我将粘贴在我负责在我的 DataGridCells 和 TextBoxes 上实现工具提示反馈的代码下方...
DataGridCell 样式:
<Style TargetType="{x:Type dg:DataGridCell}"
x:Key="DataGridCellStyle">
<Setter Property="ToolTip"
Value="{Binding Path=Column.(ToolTipService.ToolTip),RelativeSource={RelativeSource Self}}" />
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors), Converter={StaticResource ErrorContentConverter}}" />
</Trigger>
</Style.Triggers>
</Style>
文本框样式:
<Style x:Key="ValidatableTextBoxStyle" TargetType="TextBox">
<!--When the control is not in error, set the tooltip to match the AutomationProperties.HelpText attached property-->
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Mode=Self},Path=(AutomationProperties.HelpText)}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
ErrorContentConverter(用于检索工具提示的第一条验证错误消息):
Imports System.Collections.ObjectModel
Namespace Converters
<ValueConversion(GetType(ReadOnlyObservableCollection(Of ValidationError)), GetType(String))> _
Public Class ErrorContentConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
Dim errors As ReadOnlyObservableCollection(Of ValidationError) = TryCast(value, ReadOnlyObservableCollection(Of ValidationError))
If errors IsNot Nothing Then
If errors.Count > 0 Then
Return errors(0).ErrorContent
End If
End If
Return String.Empty
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
Throw New NotImplementedException()
End Function
End Class
End Namespace
...最后是在文本框中使用样式的示例:
<TextBox Text="{Binding Path=EstimatedUnits,ValidatesOnDataErrors=True,NotifyOnValidationError=True}"
Style="{StaticResource ValidatableTextBoxStyle}"
AutomationProperties.HelpText="The number of units which are likely to sell in 1 year." />
【讨论】:
几分钟前我还在看同一个样本。你的猜测是对的。在此代码示例中,他们从 TextBox 控件中删除了默认的 ErrorTemplate,因此它不会显示红色矩形。他们不使用 ErrorTemplate,而是创建 ContentProvider,其内容绑定到特定文本框的验证错误。
【讨论】:
这是我用于在工具提示中显示错误或控件旁边的小气泡的代码。
定义样式。
<Style x:Key="TextBoxValidationStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="TextboxErrorBubbleStyle" TargetType="{x:Type TextBox}" BasedOn="{StaticResource ResourceKey=TextBoxValidationStyle}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true">
<Border Background="Red" DockPanel.Dock="right" Margin="5,0,0,0" Width="10" Height="10" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="center" HorizontalAlignment="center" FontWeight="Bold" Foreground="white"/>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
<Border BorderBrush="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
与控件一起使用。
<TextBox Text="{Binding Path=FirstName, Mode=TwoWay, ValidatesOnDataErrors=True,NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextBoxValidationStyle}" Width="100" Margin="3 5 3 5"/>
<TextBox Text="{Binding Path=LastName, Mode=TwoWay, ValidatesOnDataErrors=True,NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource TextboxErrorBubbleStyle}" Width="100" Margin="0 5 3 5"/>
示例模型类。
类客户:INotifyPropertyChanged,IDataErrorInfo { 私有字符串名字; 私有字符串姓氏;
public string FirstName
{
get { return firstName; }
set
{
if (firstName != value)
{
firstName = value;
RaisePropertyChanged("FirstName");
}
}
}
public string LastName
{
get { return lastName; }
set
{
if (lastName != value)
{
lastName = value;
RaisePropertyChanged("LastName");
}
}
}
public string Error
{
get { throw new System.NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string message = null;
if (columnName == "FirstName" && string.IsNullOrEmpty(FirstName))
{
message = "Please enter FirstName";
}
if (columnName == "LastName" && string.IsNullOrEmpty(LastName))
{
message = "Please enter LastName";
}
return message;
}
}
}
用户界面外观。
【讨论】:
据我猜测,当出现错误时,Validation.ErrorTemplate="{x:Null}" 会删除红色矩形。这可能被设置为在表单启动时文本框周围没有红色矩形。
对于表单的错误显示,我在代码中的某处看到:Content="{Binding ElementName=lastNameTxt, Path=(Validation.Errors).CurrentItem}",所以,我仍然猜测它绑定到文本框(不是数据模型)并检查它是否有静态验证错误. 可能从数据模型连接到 IDataErroInfo 的错误?
我猜对了吗?
【讨论】: