修改MaterialDesign TreeViewItem选中样式时保持Expander颜色不变
WPF MaterialDesign TreeView选中状态Expander不可见问题修复
问题背景
- 开发环境:使用MaterialDesign组件库开发带TreeView控件的WPF应用
- 设计需求:TreeViewItem处于选中状态时,背景切换为红色、前景切换为白色实现高亮
- 异常表现:设置选中态前景为白色后,TreeView的Expander展开按钮会同步变为白色,但Expander所在区域背景仍为白色,导致按钮完全不可见
现有问题代码
<Style TargetType="TreeViewItem" BasedOn="{StaticResource MaterialDesignTreeViewItem}"> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Foreground" Value="White"/> <Setter Property="Background" Value="{DynamicResource Red}"/> <Setter Property="FontWeight" Value="Medium"/> </Trigger> </Style.Triggers> <Setter Property="FontSize" Value="22"/> </Style>
效果参考
- 未选中状态:

- 选中状态异常效果:

问题根源
WPF属性值会沿可视化树向下继承:
- 在TreeViewItem上设置的
Foreground=White会传递给子级的Expander ToggleButton,而Expander默认使用父级Foreground作为图标颜色,因此会同步变白 - 直接设置TreeViewItem的
Background属性时,默认仅会渲染节点文本内容所在区域的背景,不会覆盖左侧放置Expander的缩进区域,最终出现白图标+白背景的不可见问题
修复方案
方案1(推荐):整行覆盖选中背景
该方案视觉一致性最好,选中高亮会覆盖Expander所在的整行区域,符合常规TreeView交互逻辑,不需要单独修改Expander颜色。
完整实现代码:
<Style TargetType="TreeViewItem" BasedOn="{StaticResource MaterialDesignTreeViewItem}"> <Setter Property="FontSize" Value="22"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TreeViewItem"> <StackPanel> <Border x:Name="RowBorder" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" MinWidth="19"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <ToggleButton x:Name="Expander" Style="{StaticResource MaterialDesignExpandCollapseToggleStyle}" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/> <ContentPresenter x:Name="PART_Header" Grid.Column="1" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/> </Grid> </Border> <ItemsPresenter x:Name="ItemsHost" Margin="19,0,0,0"/> </StackPanel> <ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="False"> <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/> </Trigger> <Trigger Property="HasItems" Value="False"> <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/> </Trigger> <!-- 选中态整行应用红底白字 --> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="RowBorder" Property="Background" Value="{DynamicResource Red}"/> <Setter Property="Foreground" Value="White"/> <Setter Property="FontWeight" Value="Medium"/> </Trigger> <!-- 失焦选中态保留MaterialDesign默认样式 --> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="IsSelectionActive" Value="False"/> </MultiTrigger.Conditions> <Setter TargetName="RowBorder" Property="Background" Value="{DynamicResource MaterialDesignSelection}"/> <Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}"/> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
方案2(最小改动):固定Expander颜色不继承父级
如果不需要整行高亮,仅想修复Expander不可见的问题,可以直接在TreeViewItem样式中添加Expander的隐式样式,强制它使用固定颜色,不随父级Foreground变化。
在原有代码基础上修改即可:
<Style TargetType="TreeViewItem" BasedOn="{StaticResource MaterialDesignTreeViewItem}"> <!-- 单独指定Expander颜色,不继承选中态的白色前景 --> <Style.Resources> <Style TargetType="ToggleButton" BasedOn="{StaticResource MaterialDesignExpandCollapseToggleStyle}"> <Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}"/> </Style> </Style.Resources> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Foreground" Value="White"/> <Setter Property="Background" Value="{DynamicResource Red}"/> <Setter Property="FontWeight" Value="Medium"/> </Trigger> </Style.Triggers> <Setter Property="FontSize" Value="22"/> </Style>
内容的提问来源于stack exchange,提问作者adolfoanayap
相关产品推荐
相关产品推荐

