WPF用户控件如何复用内部TextBox的验证模板?
我有一个包含TextBlock和TextBox的WPF用户控件,当通过INotifyDataErrorInfo验证底层数据时,整个控件会显示红色边框。我希望让内部TextBox显示错误状态,就像直接使用TextBox时的效果(我使用的是WPF Material Design)。
用户控件XAML代码如下:
<UserControl ....> <Grid Height="40" Width="380" Margin="0,1,0,1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="110"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding ElementName=LabelWithInputUC,Path=Label}" Grid.Column="0" Margin="0,4,0,0" VerticalAlignment="Bottom"/> <TextBox VerticalAlignment="Bottom" Margin="10,0,30,0" Grid.Column="1" x:Name="ContentTextBox" MaxLength="{Binding ElementName=LabelWithInputUC,Path=MaxLength}" IsReadOnly="{Binding ElementName=LabelWithInputUC,Path=IsReadOnly}" Text="{Binding ElementName=LabelWithInputUC,Path=Text,UpdateSourceTrigger=PropertyChanged}"/> </Grid> </UserControl>
其中Label、MaxLength、IsReadOnly和Text是用户控件的依赖属性。使用该控件的窗口将Text属性绑定到ViewModel的属性,并通过INotifyDataErrorInfo进行验证。
当我尝试将TextBox设置为控件的ValidationAdornerSite后,不再显示任何验证错误。请问如何让用户控件使用内部TextBox的错误模板?
要实现让内部TextBox显示验证错误状态,需要完成以下关键操作:
1. 禁用用户控件自身的错误模板
默认情况下,用户控件会在自身渲染验证错误边框,先关闭这个行为,让错误提示转移到内部TextBox上。在UserControl标签中添加Validation.ErrorTemplate="{x:Null}":
<UserControl .... Validation.ErrorTemplate="{x:Null}"> <!-- 原有Grid内容 --> </UserControl>
2. 将内部TextBox关联为用户控件的验证装饰器目标
通过Validation.ValidationAdornerSiteFor属性,将TextBox指定为承载用户控件验证错误的容器,这样用户控件的验证错误就会渲染到TextBox上,沿用Material Design的TextBox错误样式:
<TextBox VerticalAlignment="Bottom" Margin="10,0,30,0" Grid.Column="1" x:Name="ContentTextBox" MaxLength="{Binding ElementName=LabelWithInputUC,Path=MaxLength}" IsReadOnly="{Binding ElementName=LabelWithInputUC,Path=IsReadOnly}" Text="{Binding ElementName=LabelWithInputUC,Path=Text,UpdateSourceTrigger=PropertyChanged}" Validation.ValidationAdornerSiteFor="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"/>
3. 确保Text依赖属性启用验证
检查用户控件的Text依赖属性定义,必须启用ValidatesOnNotifyDataErrors和ValidatesOnDataErrors,确保验证信息能从ViewModel传递到用户控件:
public static readonly DependencyProperty TextProperty = DependencyProperty.Register( nameof(Text), typeof(string), typeof(LabelWithInputUC), new FrameworkPropertyMetadata( default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, null, false, UpdateSourceTrigger.PropertyChanged) { ValidatesOnNotifyDataErrors = true, ValidatesOnDataErrors = true }); public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }
完成以上修改后,当ViewModel通过INotifyDataErrorInfo返回验证错误时,错误状态会正确显示在内部TextBox上,呈现Material Design的默认错误样式,而不是整个用户控件显示红边框。
内容的提问来源于stack exchange,提问作者Marcel L

