There is a margin on the left of the TreeViewItem when selected in Default TreeView style:
So i want to edit the style of TreeViewItem to make it looks like VS Solution style:
I know the default ControlTemplate of TreeViewItem is:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
</Grid>
and the left margin is from Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"
So how can I make it look like VS Solution style(keep the indent and Not to leave space of background color at the beginning )?
A very quick and simple solution would require to add a custom highlight border and give it a negative Margin
.
The following example dynamically calculates the negative left margin by listening to the Selected
routed event. To make it work the highlight Border
must span all columns and have the name "HighlightBorder"
assigned. The hosting Grid
must be named "RootGrid"
. We need to access the root grid to get the actual indention.
TreeViewItem
style:
Note that the Style is missing essential triggers to handle visibility of the ToggleButton
and the ItemsPresenter
.
<Style TargetType="TreeViewItem">
<EventSetter Event="Selected" Handler="AdjustHighlightBorder_OnSelectedItemChanged" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Border>
<Grid x:Name="RootGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Border x:Name="HighlightBorder"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
Margin="0,0,0,0"
Background="DodgerBlue"
Visibility="Hidden" />
<ToggleButton x:Name="Expander" ClickMode="Press" Content="+"
IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" />
<Border x:Name="Bd" Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}" Grid.Column="1"
Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ContentPresenter x:Name="PART_Header" ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.Column="1" Grid.Row="1" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="HighlightBorder" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Handler for the Selected
routed event:
Determine the level of the currently selected node to calculate the actual indention of the highlight border.
private void AdjustHighlightBorder_OnSelectedItemChanged(object sender, RoutedEventArgs routedEventArgs)
{
if (!(routedEventArgs.Source is TreeViewItem treeViewItemContainer
&& treeViewItemContainer.IsSelected))
{
return;
}
var highlightBorder = treeViewItemContainer.Template.FindName("HighlightBorder", treeViewItemContainer) as Border;
var rootGrid = treeViewItemContainer.Template.FindName("RootGrid", treeViewItemContainer) as Grid;
double indention = rootGrid.ColumnDefinitions.First().ActualWidth;
// Determine the level of currently selected node
int treeLevel = 0;
DependencyObject parent = treeViewItemContainer;
do
{
parent = VisualTreeHelper.GetParent(parent);
switch (parent)
{
case TreeViewItem _:
treeLevel++;
break;
case TreeView _:
// Root node reached --> apply indention
Thickness highlightBorderMargin = highlightBorder.Margin;
highlightBorderMargin.Left = treeLevel * -indention;
highlightBorder.Margin = highlightBorderMargin;
return;
}
} while (parent != null);
}