WPF TreeView:如何使用类似于资源pipe理器中的圆angular来select项目的样式

在WPF TreeView中选定的项目有一个深蓝色的背景与“尖锐”的angular落。 今天看起来有点过时了:

WPF选择有或没有焦点的TreeViewItem

我想改变背景看起来像在Windows 7的资源pipe理器(有/无焦点):

浏览器TreeViewItem被选中资源管理器TreeViewItem选择没有焦点

我到目前为止所尝试的并不是去掉原来的深蓝色背景,而是在它的顶部绘制了一个圆形边框,以便在边缘和左侧看到深蓝色 – 很难看。

在这里输入图像描述

有趣的是,当我的版本没有重点,它看起来很不错:

在这里输入图像描述

我想避免重新定义这里或这里 显示的控制模板。 我想设置所需的最小属性,使选定的项目在资源pipe理器中看起来像。

另一种select:我也很高兴有焦点的选定的项目看起来像我现在没有焦点。 当失去焦点时,颜色应该从蓝色变为灰色。

这是我的代码:

<TreeView x:Name="TreeView" ItemsSource="{Binding TopLevelNodes}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"> <TreeView.ItemContainerStyle> <Style TargetType="{x:Type TreeViewItem}"> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" /> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="BorderBrush" Value="#FF7DA2CE" /> <Setter Property="Background" Value="#FFCCE2FC" /> </Trigger> </Style.Triggers> </Style> </TreeView.ItemContainerStyle> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type viewmodels:ObjectBaseViewModel}" ItemsSource="{Binding Children}"> <Border Name="ItemBorder" CornerRadius="2" Background="{Binding Background, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" BorderThickness="1"> <StackPanel Orientation="Horizontal" Margin="2"> <Image Name="icon" Source="/ExplorerTreeView/Images/folder.png"/> <TextBlock Text="{Binding Name}"/> </StackPanel> </Border> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView> 

有了Sheridan和Meleak的优秀答案,我的TreeView现在在代码中看起来像这样(结果我非常满意,而且非常接近Explorer的风格):

 <TreeView ... <TreeView.ItemContainerStyle> <Style TargetType="{x:Type TreeViewItem}"> <!-- Style for the selected item --> <Setter Property="BorderThickness" Value="1"/> <Style.Triggers> <!-- Selected and has focus --> <Trigger Property="IsSelected" Value="True"> <Setter Property="BorderBrush" Value="#7DA2CE"/> </Trigger> <!-- Mouse over --> <Trigger Property="helpers:TreeView_IsMouseDirectlyOverItem.IsMouseDirectlyOverItem" Value="True"> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFFAFBFD" Offset="0"/> <GradientStop Color="#FFEBF3FD" Offset="1"/> </LinearGradientBrush> </Setter.Value> </Setter> <Setter Property="BorderBrush" Value="#B8D6FB"/> </Trigger> <!-- Selected but does not have the focus --> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="IsSelectionActive" Value="False"/> </MultiTrigger.Conditions> <Setter Property="BorderBrush" Value="#D9D9D9"/> </MultiTrigger> </Style.Triggers> <Style.Resources> <Style TargetType="Border"> <Setter Property="CornerRadius" Value="2"/> </Style> </Style.Resources> </Style> </TreeView.ItemContainerStyle> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type viewmodels:ObjectBaseViewModel}" ItemsSource="{Binding Children}"> <StackPanel Orientation="Horizontal" Margin="2,1,5,2"> <Grid Margin="0,0,3,0"> <Image Name="icon" Source="/ExplorerTreeView/Images/folder.png"/> </Grid> <TextBlock Text="{Binding Name}" /> </StackPanel> </HierarchicalDataTemplate> <!-- Brushes for the selected item --> <LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFDCEBFC" Offset="0"/> <GradientStop Color="#FFC1DBFC" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="{x:Static SystemColors.ControlBrushKey}" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFF8F8F8" Offset="0"/> <GradientStop Color="#FFE5E5E5" Offset="1"/> </LinearGradientBrush> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" /> <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" /> </TreeView.Resources> </TreeView> 

join@ Sheridan的答案
这不是100%的准确,但应该让你非常接近(它使用的GridView的颜色是非常接近的Windows资源pipe理器)

在这里输入图像描述

 <TreeView ...> <TreeView.Resources> <LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFD9F4FF" Offset="0"/> <GradientStop Color="#FF9BDDFB" Offset="1"/> </LinearGradientBrush> <LinearGradientBrush x:Key="{x:Static SystemColors.ControlBrushKey}" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFEEEDED" Offset="0"/> <GradientStop Color="#FFDDDDDD" Offset="1"/> </LinearGradientBrush> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" /> <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" /> </TreeView.Resources> <TreeView.ItemContainerStyle> <Style TargetType="{x:Type TreeViewItem}"> <Setter Property="BorderThickness" Value="1.5"/> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="BorderBrush" Value="#adc6e5"/> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True"/> <Condition Property="IsSelectionActive" Value="False"/> </MultiTrigger.Conditions> <Setter Property="BorderBrush" Value="LightGray"/> </MultiTrigger> </Style.Triggers> <Style.Resources> <Style TargetType="Border"> <Setter Property="CornerRadius" Value="2"/> </Style> </Style.Resources> </Style> </TreeView.ItemContainerStyle> </TreeView> 

添加到您的TreeView.ContainerStyle删除默认的blue背景。

 <Style.Resources> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" /> <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" /> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" /> <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" /> </Style.Resources> 

您可以用您希望您的项目文本和选定的项目文本的颜色replaceBlack

为了在未聚焦的情况下具有灰色背景,可以使用灰色backgorund设置“非聚焦” Style ,并在TreeViewItem.GotFocusLostFocus事件上使用EventTriggerStyle之间切换。

编辑>>>

如果你想闪光,你可以使用animation在背景颜色之间ItemBorder Border直接在你的HierarchicalDataTemplate添加触发器到你的ItemBorder Border ,就像这样:

 <Border.Triggers> <EventTrigger RoutedEvent="Border.GotFocus"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="YourColour" Duration="0:0:0.2" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Border.LostFocus"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="LightGray" Duration="0:0:0.2" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Border.Triggers> 

请注意,这只有在ColorAnimation具有From颜色的情况下才有效。 如代码所示,运行时将在Border.Background属性中查找设置的SolidColorBrush ,因此您必须设置一个。 您可以直接设置ColorAnimation.From属性。

Windows 10的TreeView (和ListView)样式

我最初正在寻找一种将Windows 10颜色scheme应用于TreeViewItem的方法,其中包括

  • IsMouseOver只在当前项目上
  • Windows 10的颜色,WPF已经将它们应用到列表框(而不是Windows资源pipe理器)

如果您有任何人正在寻找这个,请随时采取下面的代码。 我使用Helge Klein的IsMouseOver问题解决scheme,并将Windows 10颜色应用于XAML。 因此,我build议将此作为对已接受答案的补充。

另外,请看下面的ListViewComboBox


截图

例

App.xaml中

 <Style TargetType="{x:Type TreeView}"> <Style.Resources> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#CBE8F6" /> <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="#F6F6F6" /> <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" /> <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" /> </Style.Resources> </Style> <Style TargetType="{x:Type TreeViewItem}"> <Setter Property="BorderThickness" Value="1" /> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="BorderBrush" Value="#26A0DA" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="local:TreeViewItemHelper.IsMouseDirectlyOverItem" Value="True" /> <Condition Property="IsSelected" Value="False" /> </MultiTrigger.Conditions> <Setter Property="Background" Value="#E5F3FB" /> <Setter Property="BorderBrush" Value="#70C0E7" /> </MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True" /> <Condition Property="IsSelectionActive" Value="False" /> </MultiTrigger.Conditions> <Setter Property="BorderBrush" Value="#DADADA" /> </MultiTrigger> </Style.Triggers> </Style> 

TreeViewItemHelper (由Helge Klein发布, 稍作修改/简化

 public static class TreeViewItemHelper { private static TreeViewItem CurrentItem; private static readonly RoutedEvent UpdateOverItemEvent = EventManager.RegisterRoutedEvent("UpdateOverItem", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItemHelper)); private static readonly DependencyPropertyKey IsMouseDirectlyOverItemKey = DependencyProperty.RegisterAttachedReadOnly("IsMouseDirectlyOverItem", typeof(bool), typeof(TreeViewItemHelper), new FrameworkPropertyMetadata(null, new CoerceValueCallback(CalculateIsMouseDirectlyOverItem))); public static readonly DependencyProperty IsMouseDirectlyOverItemProperty = IsMouseDirectlyOverItemKey.DependencyProperty; static TreeViewItemHelper() { EventManager.RegisterClassHandler(typeof(TreeViewItem), UIElement.MouseEnterEvent, new MouseEventHandler(OnMouseTransition), true); EventManager.RegisterClassHandler(typeof(TreeViewItem), UIElement.MouseLeaveEvent, new MouseEventHandler(OnMouseTransition), true); EventManager.RegisterClassHandler(typeof(TreeViewItem), UpdateOverItemEvent, new RoutedEventHandler(OnUpdateOverItem)); } public static bool GetIsMouseDirectlyOverItem(DependencyObject obj) { return (bool)obj.GetValue(IsMouseDirectlyOverItemProperty); } private static object CalculateIsMouseDirectlyOverItem(DependencyObject item, object value) { return item == CurrentItem; } private static void OnUpdateOverItem(object sender, RoutedEventArgs e) { CurrentItem = sender as TreeViewItem; CurrentItem.InvalidateProperty(IsMouseDirectlyOverItemProperty); e.Handled = true; } private static void OnMouseTransition(object sender, MouseEventArgs e) { lock (IsMouseDirectlyOverItemProperty) { if (CurrentItem != null) { DependencyObject oldItem = CurrentItem; CurrentItem = null; oldItem.InvalidateProperty(IsMouseDirectlyOverItemProperty); } Mouse.DirectlyOver?.RaiseEvent(new RoutedEventArgs(UpdateOverItemEvent)); } } } 

ListBox / ListView和ComboBox:在Windows 7 (和8?)中 ,这将导致从TreeView到ListBox / ListView和ComboBox的devise不同。 因此,如果您也想将这种配色scheme应用于这些控制types,请使用以下命令:

 <Style TargetType="{x:Type ListBoxItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <Border Name="Border" BorderThickness="1" Background="Transparent"> <ContentPresenter /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Border" Property="Background" Value="#E5F3FB" /> <Setter TargetName="Border" Property="BorderBrush" Value="#70C0E7" /> </Trigger> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="Border" Property="Background" Value="#CBE8F6" /> <Setter TargetName="Border" Property="BorderBrush" Value="#26A0DA" /> </Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="True" /> <Condition Property="Selector.IsSelectionActive" Value="False" /> </MultiTrigger.Conditions> <Setter TargetName="Border" Property="Background" Value="#F6F6F6" /> <Setter TargetName="Border" Property="BorderBrush" Value="#DADADA" /> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}" /> <Style TargetType="{x:Type ComboBoxItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ComboBoxItem}"> <Border Name="Border" BorderThickness="1" Padding="1" Background="Transparent"> <ContentPresenter /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Border" Property="Background" Value="#E5F3FB" /> <Setter TargetName="Border" Property="BorderBrush" Value="#70C0E7" /> </Trigger> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="Border" Property="Background" Value="#CBE8F6" /> <Setter TargetName="Border" Property="BorderBrush" Value="#26A0DA" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>