TextBox Header模板绑定Errors数据失效问题及通用模板需求
我尝试给TextBox制作自定义Header模板,要求除显示文本框名称外,还要展示错误信息,但模板内这段代码始终无效:
<TextBlock Text="{x:Bind Errors, Mode=OneWay}" Foreground="Green" />
它一直显示为空。
但不在Header模板内的近乎相同代码却能正常工作:
<TextBlock Text="{x:Bind Supplier.Errors, Mode=OneWay}" Foreground="Green" Grid.Row="7" Grid.Column="1" />
当前程序触发错误时的显示效果:
我希望底部的绿色文本“Name should be longer...”能显示在TextBox顶部Header模板的“Errors: ”旁。同时想做一个通用版本,通过资源字典中的样式或模板应用到所有TextBox,让它们的Header都能显示错误信息。
我的示例样式代码:
<Style TargetType="TextBox" x:Key="ValidatedTextBox"> <Setter Property="HeaderTemplate"> <Setter.Value> <DataTemplate> <StackPanel Orientation="Horizontal"> <ContentControl Content="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}" /> <TextBlock Text="{Binding Errors, RelativeSource={RelativeSource Mode=TemplatedParent}}" /> </StackPanel> </DataTemplate> </Setter.Value> </Setter> </Style>
对应当前显示效果的XAML代码:
<TextBox x:Name="NameTextBox" Header="Name" PlaceholderText="Enter Name" PlaceholderForeground="Gray" IsColorFontEnabled="True" Text="{x:Bind Supplier.Name, Mode=TwoWay}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"> <TextBox.HeaderTemplate > <DataTemplate x:DataType="models:Supplier"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding}" Foreground="Red" /> <TextBlock>Errors: </TextBlock> <TextBlock Text="{x:Bind Errors, Mode=OneWay}" Foreground="Green" /> </StackPanel> </DataTemplate> </TextBox.HeaderTemplate> </TextBox> <TextBox Style="{StaticResource ValidatedTextBox}" Header="Ciao" Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2"/> <TextBlock Text="Name Errors: " Grid.Row="7" Grid.Column="0" /> <TextBlock Text="{x:Bind Supplier.Errors, Mode=OneWay}" Foreground="Green" Grid.Row="7" Grid.Column="1" /> <TextBlock Text="{x:Bind Supplier.Name, Mode=OneWay}" Foreground="Green" Grid.Row="8" Grid.Column="0" /> <Button Click="Button_Click" Content="Click" Grid.Row="8" Grid.Column="1"/>
解决方案
问题根源
HeaderTemplate的DataTemplate默认数据上下文是Header的内容(比如你设置的Header="Name"字符串),而非TextBox绑定的数据源(Supplier对象)。直接用{x:Bind Errors}找不到对应属性,所以显示为空。
单个TextBox的修复方案
修改HeaderTemplate中的绑定逻辑,通过RelativeSource找到父级TextBox,再绑定到它的DataContext(即Supplier)的Errors属性:
<TextBox x:Name="NameTextBox" Header="Name" ...> <TextBox.HeaderTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <!-- 显示原Header文本 --> <TextBlock Text="{Binding}" Foreground="Red" Margin="0 0 8 0"/> <TextBlock>Errors: </TextBlock> <!-- 绑定到TextBox的DataContext.Errors --> <TextBlock Text="{Binding DataContext.Errors, RelativeSource={RelativeSource AncestorType=TextBox}, Mode=OneWay}" Foreground="Green"/> </StackPanel> </DataTemplate> </TextBox.HeaderTemplate> </TextBox>
无需设置x:DataType="models:Supplier",因为通过RelativeSource跨层级绑定已直接指向TextBox的DataContext。
通用样式版本(资源字典)
要实现通用模板,核心是让HeaderTemplate能获取到TextBox的DataContext,同时保留原Header文本显示:
<Style TargetType="TextBox" x:Key="ValidatedTextBox"> <Setter Property="HeaderTemplate"> <Setter.Value> <DataTemplate> <StackPanel Orientation="Horizontal"> <!-- 显示原Header内容 --> <ContentPresenter Content="{Binding}" Margin="0 0 8 0"/> <!-- 绑定到TextBox的DataContext.Errors --> <TextBlock Text="{Binding DataContext.Errors, RelativeSource={RelativeSource AncestorType=TextBox}, Mode=OneWay}" Foreground="Green"/> </StackPanel> </DataTemplate> </Setter.Value> </Setter> </Style>
可选优化:错误为空时隐藏提示
如果希望错误信息为空时不显示“Errors: ”文本,可添加嵌套StackPanel并绑定Visibility:
<DataTemplate> <StackPanel Orientation="Horizontal"> <ContentPresenter Content="{Binding}" Margin="0 0 8 0"/> <StackPanel Orientation="Horizontal" Visibility="{Binding DataContext.Errors, RelativeSource={RelativeSource AncestorType=TextBox}, Converter={StaticResource StringToVisibilityConverter}}"> <TextBlock Text="Errors: " Margin="0 0 4 0"/> <TextBlock Text="{Binding DataContext.Errors, RelativeSource={RelativeSource AncestorType=TextBox}, Mode=OneWay}" Foreground="Green"/> </StackPanel> </StackPanel> </DataTemplate>
需要提前在资源字典中定义StringToVisibilityConverter:
<converters:StringToVisibilityConverter x:Key="StringToVisibilityConverter"/>
转换器C#代码:
public class StringToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { return string.IsNullOrEmpty(value as string) ? Visibility.Collapsed : Visibility.Visible; } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }
关键说明
RelativeSource AncestorType=TextBox:让绑定向上查找父级TextBox控件,获取其DataContext(即你的Supplier实例)。- 通用样式无需指定
x:DataType,可适配所有带有Errors属性的数据源类型。
内容的提问来源于stack exchange,提问作者Nuvolari

