如何将实现IDataErrorInfo的视图模型绑定到UserControl并传播验证错误

本文关键字:UserControl 传播 错误 验证 绑定 模型 实现 IDataErrorInfo 视图 | 更新日期: 2023-09-27 17:53:34

我写了一个UserControl,它暴露了一些依赖属性来修改控件的布局(即认为它是一个通用的类型安全的编辑器控件-所以我的数据类型是日期(通过日期选择器编辑),枚举(通过组合框编辑)和数字(通过文本框编辑)。我还将3个编辑器控件的值作为依赖项属性公开,以便它可以被绑定。

usercontrol中的控件都绑定到暴露的依赖属性以获得它们的值(必要时使用适当的转换器)。

该控件构成了绑定到视图模型的较大UI的一小部分-要编辑的值,自定义控件的数据类型标志以及可能的有效值列表都绑定到视图模型中的对象。

我的问题是这样的:我已经在视图模型上实现了IDataErrorInfo,并在自定义usercontrol中设置了控件的绑定,使其具有ValidatesOnDataErrors=True, NotifyOnValidationError=True,但验证不显示。

这是我的用户控件的XAML(除了依赖属性声明之外没有其他代码隐藏逻辑):

<UserControl.Resources>
    <!-- Converters -->
    <local:ValidationBooleanToImageConverter x:Key="ValidationBooleanToImageConverter"/>
    <local:ValidationErrorToStringConverter x:Key="ValidationErrorToStringConverter"/>
    <local:DataTypeToVisibilityConverter DataType="Date" x:Key="DateDataTypeToVisibilityConverter"/>
    <local:DataTypeToVisibilityConverter DataType="Numeric" x:Key="NumericDataTypeToVisibilityConverter"/>
    <local:DataTypeToVisibilityConverter DataType="Enumeration" x:Key="EnumerationDataTypeToVisibilityConverter"/>
    <local:DateToStringConverter x:Key="DateToStringConverter"/>
    <!-- Styles -->
    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip"
                        Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors).CurrentItem, Converter={StaticResource ResourceKey=ValidationErrorToStringConverter}}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition Width="16"/>
    </Grid.ColumnDefinitions>
    <toolkit:DatePicker Height="25" Margin="0,0,5,0" Visibility="{Binding Path=DataType, ElementName=UserControl, Converter={StaticResource ResourceKey=DateDataTypeToVisibilityConverter}}" SelectedDate="{Binding Path=Value, ElementName=UserControl, Converter={StaticResource ResourceKey=DateToStringConverter}}"/>
    <ComboBox Height="25" Margin="0,0,5,0" Visibility="{Binding Path=DataType, ElementName=UserControl, Converter={StaticResource ResourceKey=EnumerationDataTypeToVisibilityConverter}}" SelectedItem="{Binding Path=Value, ElementName=UserControl, Mode=TwoWay}" ItemsSource="{Binding Path=Items, ElementName=UserControl}" />
    <TextBox x:Name="_txtValue" Height="25" Margin="0,0,5,0" Visibility="{Binding Path=DataType, ElementName=UserControl, Converter={StaticResource ResourceKey=NumericDataTypeToVisibilityConverter}}" Text="{Binding Path=Value, ElementName=UserControl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}"/>
    <Image Grid.Column="2" Grid.Row="0" Source="{Binding ElementName=_txtValue, Path=(Validation.HasError), Converter={StaticResource ResourceKey=ValidationBooleanToImageConverter} }" ToolTip="{Binding ElementName=_txtValue, Path=ToolTip}" Width="16" Height="16"/>
</Grid>

…而来自大视图的usercontrol引用是…

<control:ValueEditorControl DataType="{Binding Path=ContextualSelectedTagDataType}" Items="{Binding Path=ContextualSelectedTagItems}" Value="{Binding Path=ContextualSelectedTagDataObjectValue, Mode=TwoWay}" Height="25" VerticalAlignment="Top"/>
谁能给我指个正确的方向?

如何将实现IDataErrorInfo的视图模型绑定到UserControl并传播验证错误

您的虚拟机是否实现INotifyPropertyChanged ?即使你实现了IDataErrorInfo,如果WPF没有被通知到VM的变化,那么它就不会绑定到这些变化。

话虽如此,我将把你的工具提示设置为:

<Setter Property="ToolTip"
            Value="{Binding RelativeSource={RelativeSource Self}, 
                   Path=(Validation.Errors)[0].ErrorContent}"/>

如果你想要整个样式,我推荐这样:

<Style TargetType="{x:Type TextBox}">
    <Setter Property="Validation.ErrorTemplate">
        <Setter.Value>
            <ControlTemplate>
                <AdornedElementPlaceholder Name="controlWithError" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="Background" Value="LightPink"/>
            <Setter Property="ToolTip"
            Value="{Binding RelativeSource={RelativeSource Self}, 
                   Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
    </Style.Triggers>
</Style>