Introduction

This article describe how to style the WPF TreeView so it looks like the one in Windows 7 File Explorer, I basically included 3 changes :

  • Reduced indent spacing
  • Full line selection indicator
  • Auto fade expander arrows

How to use?

  • Include W7TreeViewItem.xaml and W7TreeViewItemUtils.cs.
  • Change the ItemContainerStyle of your TreeView.
  • <Setter Property="ItemContainerStyle">
      <Setter.Value>
        <Style TargetType="{x:Type TreeViewItem}"
               BasedOn="{StaticResource W7TreeViewItemStyle}">
        ...
      </Setter.Value>
    </Setter>
  • Enable W7TreeViewItemUtils.IsEnabled property for your TreeView, who will hook MouseEnter and MouseLeave event.
    W7TreeViewItemUtils.SetIsEnabled(this, true);

Reduced Indent Spacing

This is simple, all you need is to modify the ControlTemplate (You can look for it from MSDN, or use the “Edit a copy” function in Blend), You can find an ItemsPresenter inside the Template, which is used to list subitems, all you need is to change it’s Grid.Column to 0 (from 1), ColumnSpan to 3 (from 2) and set some Margin in the left side.

<ItemsPresenter x:Name="ItemsHost" Margin="8,0,0,0"
      Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" />

Full line Selection Indicator

The default indicator occupy only the area of it’s contents, which in this case, icon and text, this is because the parent TreeViewItem occupy only that area, so changing the background doesnt work.

You may want to set HorizontalAlighment to Stretch, so the TreeViewItem occupy as much area as possible, it seems to work at first, but as you see above, subitems are placed in ItemsPresenter, and ItemsPresenter is allocated with a margin, which is 8 pts per level.

So the only way to deal with this is to use RenderTransform. Using RenderTransform you can change how it render, if I use ScaleTransform and set ScaleX to negative value, it will render from right to left (like a mirror).

Unlike LayoutTransform, RenderTransform affects the display only, so it wont change the size of the TreeView.

<Border Padding="{TemplateBinding Padding}" Grid.Column="0" Grid.ColumnSpan="3">
  <Grid x:Name="BdGrid" >
    <Grid.RowDefinitions>
      <RowDefinition MaxHeight="11"/>
      <RowDefinition/>
    </Grid.RowDefinitions>
    <Border x:Name="Bd" SnapsToDevicePixels="true"
            Background="{StaticResource SelectedBackgroundBrush}"  Grid.RowSpan="2"
            Visibility="Collapsed" BorderThickness="0,1" BorderBrush="#FFCCF0FF" />
    <Rectangle x:Name="BdUpperHighlight" Fill="#75FFFFFF" Visibility="Collapsed" />
    <Border x:Name="Bd2" SnapsToDevicePixels="true" ...Same as Bd... >
      <Border.RenderTransform>
        <TransformGroup>
          <ScaleTransform ScaleX="-2" />
        </TransformGroup>
      </Border.RenderTransform>
    </Border>
    <Rectangle x:Name="Bd2UpperHighlight" ...Same as BdUpperHighlight... >
      <Rectangle.RenderTransform>
        <TransformGroup>
          <ScaleTransform ScaleX="-2" />
        </TransformGroup>
      </Rectangle.RenderTransform>
    </Rectangle>
  </Grid>
</Border>

The UpperHighlight is found in above is required to make the upper part of the background look lighter (like Aero controls).

Auto fade Expander arrows

The expander arrow is only shown when the mouse cursor enter the TreeView (IsMouseOver), the expander then disappear slowly when cursor leave.

You cannot create a EventTrigger that intercept MouseEnterEvent from the TreeView, it can only intercept the item’s MouseEnterEvent, even you set TreeView.MouseEnterEvent.

So I created an attached property W7TreeViewItemUtils.IsEnabled, when set to true, will change another attached property W7TreeViewItemUtils.ArrowOpacity when mouse enter and leave the TreeView.   On the another side, ArrowOpacity is also bound by the TreeViewItem, so it will slowly disappear when TreeView’s ArrowOpacity is set from 1 to 0 using a DoubleAnimation.

The final product can be found in my FileExplorer article (0.6).