0

In WPF, when you have a ListView passing over an item with the mouse will give a nice highlight effect, like this:

enter image description here

However, this doesn't happen with a TreeView. My question is simple: how do I enable the same effect for the items in a TreeView?

NOTE: I'm aware of these questions: WPF TreeView Highlight Row On Hover Highlight whole TreeViewItem line in WPF

But they are mainly concerned with extending the highlight behavior to the entire row, while I still can't figure out how to enable the highlight effect on a single TreeViewItem (that would be more than enough for me)

Community
  • 1
  • 1
Master_T
  • 7,232
  • 11
  • 72
  • 144

1 Answers1

7

Normally we can add some style for the TreeViewItem with some Trigger to toggle the Background on mouse over. However it's not such simple when TreeViewItem contains each other (nested) and the bubbling of the event will cause some unwanted effect. I've tried digging in solving the problem with this approach but no luck (just nearly solve it but not perfectly).

So we have to use another approach, here we will change the template of the Header by setting the HeaderTemplate of TreeViewItem. In that template, we will add triggers such as for the root Border and then everything works OK:

<TreeView>
   <TreeView.Resources>
       <Style TargetType="TreeViewItem">
          <Setter Property="HeaderTemplate">
              <Setter.Value>
                <DataTemplate>  
                  <Border>
                     <TextBlock Text="{Binding}"/>
                     <Border.Style>
                       <Style TargetType="Border">
                         <Setter Property="BorderThickness" Value="1"/>
                         <Setter Property="BorderBrush" Value="Transparent"/>
                         <Style.Triggers>
                           <MultiDataTrigger>
                           <MultiDataTrigger.Conditions>
                             <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                                  Path=IsMouseOver}" Value="True"/>
                             <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem},
                                                  Path=IsSelected}" Value="False"/>
                           </MultiDataTrigger.Conditions>
                           <Setter Property="Background" Value="#ffe5f3fb"/>
                           <Setter Property="BorderBrush" Value="#ffa5d7f0"/>
                           </MultiDataTrigger>
                         </Style.Triggers>
                       </Style>
                      </Border.Style>
                    </Border>
                  </DataTemplate>
                </Setter.Value>
             </Setter>              
       </Style>
   </TreeView.Resources>
   <TreeViewItem Header="Item 1">
      <TreeViewItem Header="Item 11"></TreeViewItem>
      <TreeViewItem Header="Item 12"/>
   </TreeViewItem>
   <TreeViewItem Header="Item 2">
   </TreeViewItem>
</TreeView>

Note that you can create whatever Brush you like to replace the simple SolidColorBrush I used above for the Background. You should read more about Brush in WPF.

Update: As far as I know to synchronize with the System settings about colors and brushes, we just have the static class SystemColors. The closest color I've found for the hovering highlight is SystemColors.HotTrackColorKey. However I guess the hovering highlight used for the ListView in Windows 7 applies some opacity for the brush and it looks lighter. So I've tried using the opacity of 0.05 for the brush and it looks fairly close to the default highlight color of ListView in Windows 7. You can define the brush in the resource and use it like this:

//inside the Style for Border
<Style.Resources>
    <SolidColorBrush x:Key="hoverBrush" Opacity=".05" 
             Color="{DynamicResource {x:Static SystemColors.HotTrackColorKey}}"/>
</Style.Resources>

Then set the brush for background via Setter:

<Setter Property="Background" Value="{DynamicResource hoverBrush}"/>
King King
  • 61,710
  • 16
  • 105
  • 130
  • This "kinda" works, but it has two problems: 1) The highlight brush is just a color. Is there a brush that gives that nice background+border effect like in the picture I posted? Or do I have to set a border manually? 2) If you hover over a sub-item in the tree the parent(s) get highlighted as well, which looks weird – Master_T Sep 19 '14 at 11:00
  • @Master_T I've just realized that there is 1 problem, that's the parent of hovered item is also highlighted (which may not be what you want), so what's the other problem? – King King Sep 19 '14 at 11:02
  • I was editiing, the other problem is exactly what you mentioned. I read on other answers that this should be fixed by adding TargetName="Bd" to the setter's attributes, but this breaks compilation for me ("TargetName property cannot be set on a style setter") – Master_T Sep 19 '14 at 11:05
  • @Master_T see my updated code. I think it's the ***simplest*** solution you can have. In fact other solutions may not be more complex but it requires you to import a large file of default template into your project. – King King Sep 19 '14 at 18:57
  • Thanks for the input, your new code works (it was conflicting with my ItemTemplate, but I refactored it a bit and now it's perfect). One question, if you know: is there a default brush for the border and background color of an "hovered" item, or must I input it manually? I ask because on different windows versions they might decide to change it... is there a way to know the correct colors in code? I checked the ones in SystemColors class but there doesn't seem to be one that matches the ListView one (the one I show in the picture). – Master_T Sep 20 '14 at 14:27
  • @Master_T I think `SystemColors` is the only thing we can play with relating to that issue. See my update for how, I guess the key point is we need some opacity for the brush. – King King Sep 20 '14 at 15:21