如何根据IsValid状态修改ItemsControl内TextBlock与TextBox的前景色?
问题描述
我定义了如下类:
public class ShippingMethodMap { public string ShippingMethod { get; set; } public int? MethodId { get; set; } public bool IsManaged { get; set; } public bool IsValid { get; set; } }
数据存储在ObservableCollection<ShippingMethodMap> ShippingMethodMapCollection中,并通过以下XAML代码展示:
<ItemsControl ItemsSource="{Binding Path=ShippingMethodMapCollection}"> <ItemsControl.ItemTemplate> <DataTemplate> <Border Margin="1" BorderThickness="1" BorderBrush="LightGray"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{Binding Path=ShippingMethod}"> </TextBlock> <TextBox Grid.Column="1" Text="{Binding Path=MethodId}" IsEnabled="{Binding Path=IsManaged}"> </TextBox> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
请问当ShippingMethodMap.IsValid为false时,如何将对应项的TextBlock和TextBox的前景色设置为红色?
解决方案
可以通过WPF的DataTrigger实现这个需求,下面提供几种常用的实现方式:
方式一:通过父元素继承前景色(最简洁)
利用WPF的属性继承特性,给外层Border添加DataTrigger,当IsValid为false时设置前景色为红色,内部的TextBlock和TextBox会自动继承这个属性:
<ItemsControl ItemsSource="{Binding Path=ShippingMethodMapCollection}"> <ItemsControl.ItemTemplate> <DataTemplate> <Border Margin="1" BorderThickness="1" BorderBrush="LightGray"> <Border.Style> <Style TargetType="Border"> <Style.Triggers> <DataTrigger Binding="{Binding IsValid}" Value="False"> <Setter Property="Foreground" Value="Red"/> </DataTrigger> </Style.Triggers> </Style> </Border.Style> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{Binding Path=ShippingMethod}"> </TextBlock> <TextBox Grid.Column="1" Text="{Binding Path=MethodId}" IsEnabled="{Binding Path=IsManaged}"> </TextBox> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
方式二:定义共享样式复用逻辑
在Grid的资源中定义通用样式,让TextBlock和TextBox共用这个样式,避免重复代码:
<ItemsControl ItemsSource="{Binding Path=ShippingMethodMapCollection}"> <ItemsControl.ItemTemplate> <DataTemplate> <Border Margin="1" BorderThickness="1" BorderBrush="LightGray"> <Grid> <Grid.Resources> <Style TargetType="FrameworkElement" x:Key="InvalidForegroundStyle"> <Style.Triggers> <DataTrigger Binding="{Binding IsValid}" Value="False"> <Setter Property="Foreground" Value="Red"/> </DataTrigger> </Style.Triggers> </Style> </Grid.Resources> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{Binding Path=ShippingMethod}" Style="{StaticResource InvalidForegroundStyle}"> </TextBlock> <TextBox Grid.Column="1" Text="{Binding Path=MethodId}" IsEnabled="{Binding Path=IsManaged}" Style="{StaticResource InvalidForegroundStyle}"> </TextBox> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
注:TextBlock和TextBox都继承自FrameworkElement,因此这个通用样式可同时作用于两者。
方式三:单独给每个控件添加触发器
如果不需要复用样式,可直接给TextBlock和TextBox分别添加DataTrigger:
<ItemsControl ItemsSource="{Binding Path=ShippingMethodMapCollection}"> <ItemsControl.ItemTemplate> <DataTemplate> <Border Margin="1" BorderThickness="1" BorderBrush="LightGray"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{Binding Path=ShippingMethod}"> <TextBlock.Style> <Style TargetType="TextBlock"> <Style.Triggers> <DataTrigger Binding="{Binding IsValid}" Value="False"> <Setter Property="Foreground" Value="Red"/> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> <TextBox Grid.Column="1" Text="{Binding Path=MethodId}" IsEnabled="{Binding Path=IsManaged}"> <TextBox.Style> <Style TargetType="TextBox"> <Style.Triggers> <DataTrigger Binding="{Binding IsValid}" Value="False"> <Setter Property="Foreground" Value="Red"/> </DataTrigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
内容的提问来源于stack exchange,提问作者Alexey Titov
相关产品推荐
相关产品推荐

