如何修改带自定义前景色的TreeView选中项前景色?
TreeView选中项文本颜色不更新的纯XAML解决方案
问题描述
我有一个带自定义样式项的TreeView,示例代码如下:
<TreeView ItemsSource="{Binding DisplayItems}"> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type vmw:ManagedObjectViewModel}"> <Grid> <StackPanel Orientation="Horizontal" Visibility="{Binding Name, Converter={StaticResource EmptyStringToVisibilityConverter}}"> <TextBlock Style="{StaticResource NameText}" Text="{Binding Name}" /> <TextBlock Style="{StaticResource ClassNameText}"> <TextBlock.Inlines> <Run Text=" (" /> <Run Text="{Binding ClassName, Mode=OneWay}" /> <Run Text=")" /> </TextBlock.Inlines> </TextBlock> </StackPanel> <TextBlock Style="{StaticResource ClassNameText}" Text="{Binding ClassName}" Visibility="{Binding Name, Converter={StaticResource InverseEmptyStringToVisibilityConverter}}" /> </Grid> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView>
这些项包含两个文本块,分别显示黑色和灰色文本。但选中TreeView项时,文本块依然保留原有前景色——原因是样式里设置的Foreground覆盖了从TreeViewItem继承的颜色值。
我不想修改ViewModel(之前想到的方案需要给TreeViewItem加样式绑定选中状态到VM,再用转换器切换颜色,太复杂),有没有更简洁的纯XAML解决方案?
解决方案
方法1:通过相对绑定+触发器动态切换颜色
直接修改文本块的样式,添加触发器绑定到父级TreeViewItem的选中状态,实现颜色切换:
针对NameText样式:
<Style x:Key="NameText" TargetType="TextBlock"> <Setter Property="Foreground" Value="Black" /> <Style.Triggers> <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" Value="True"> <Setter Property="Foreground" Value="White" /> </DataTrigger> </Style.Triggers> </Style>
针对ClassNameText样式:
<Style x:Key="ClassNameText" TargetType="TextBlock"> <Setter Property="Foreground" Value="Gray" /> <Style.Triggers> <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" Value="True"> <Setter Property="Foreground" Value="White" /> </DataTrigger> </Style.Triggers> </Style>
这种方式完全通过XAML实现,不需要修改任何ViewModel代码。
方法2:重写TreeViewItem模板确保颜色继承
如果方法1不生效,可能是TreeViewItem的默认模板没有正确传递选中状态的前景色,可以重写其ControlTemplate:
<Style TargetType="TreeViewItem"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TreeViewItem"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <!-- 展开折叠箭头 --> <ToggleButton x:Name="Expander" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource TreeViewItemExpanderStyle}" /> <!-- 内容容器 --> <Border x:Name="Bd" Grid.Column="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"> <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" /> </Border> <!-- 子项容器 --> <ItemsPresenter x:Name="ItemsHost" Grid.Column="1" Grid.Row="1" Margin="10,0,0,0" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" /> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
然后保留文本块的默认颜色样式即可:
<Style x:Key="NameText" TargetType="TextBlock"> <Setter Property="Foreground" Value="Black" /> </Style> <Style x:Key="ClassNameText" TargetType="TextBlock"> <Setter Property="Foreground" Value="Gray" /> </Style>
此时TreeViewItem选中时,会自动将前景色设为系统高亮文本色(默认白色),文本块会继承这个值,覆盖自身默认颜色。
内容的提问来源于stack exchange,提问作者Spook
相关产品推荐
相关产品推荐

