Strange issues I faced.
When trying to use StaticResource
or x:Static
with a converter from ControlTemplate.Trigger
the converter value
is always NULL
.
In the below example the different usages are shown without any issues:
<StackPanel Orientation="Horizontal">
<ContentControl Content="{DynamicResource Plus}"/>
<ContentControl Content="{DynamicResource Minus}"/>
<ContentControl Content="{Binding Source={StaticResource Plus}}"/>
<ContentControl Content="{Binding Source={StaticResource Minus}}"/>
<ContentControl Content="{Binding Source={StaticResource Plus}, Converter={StaticResource ToRed}}"/>
<ContentControl Content="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<ContentControl Content="{x:Static icon:Icons.Plus}"/>
<ContentControl Content="{x:Static icon:Icons.Minus}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}, Converter={StaticResource ToRed}}"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}, Converter={StaticResource ToRed}}"/>
</StackPanel>
The above code results in:
so far all good, both the StaticResouce
and x:Static
works fine, but the same examples when used within a ControlTemplate.Triggers
then the converter gets NULL
as VALUE
This is tested in .NET 4.5, 4.7.2 and 4.8 in VS 16.11.15 (2019)
To reproduce:
MyResources.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Viewbox x:Key="Minus" x:Shared="False" Stretch="Uniform">
<Canvas Width="32" Height="32" Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19" Height="19" Canvas.Left="6.49999" Canvas.Top="6.5" Stretch="Fill" StrokeMiterLimit="2.75" Stroke="#FF575756"/>
<Rectangle Width="9" Height="2" Canvas.Left="11.5" Canvas.Top="15" Stretch="Fill" Fill="#FF1E5AA0"/>
</Canvas>
</Viewbox>
<Viewbox x:Key="Plus" x:Shared="False" Stretch="Uniform">
<Canvas Width="32" Height="32" Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19" Height="19" Canvas.Left="6.49999" Canvas.Top="6.5" Stretch="Fill" StrokeMiterLimit="2.75" Stroke="#FF575756"/>
<Path Width="9" Height="9" Canvas.Left="11.5" Canvas.Top="11.5" Stretch="Fill" Fill="#FF1E5AA0" Data="F1 M 20.5,15L 17,15L 17,11.5L 15,11.5L 15,15L 11.5,15L 11.5,17L 15,17L 15,20.5L 17,20.5L 17,17L 20.5,17L 20.5,15 Z "/>
</Canvas>
</Viewbox>
</ResourceDictionary>
Static classes
//STATIC CLASS TO GET ICONS via x:Static
public static class Icons
{
public static UIElement Minus => GetIconByName("Minus");
public static UIElement Plus => GetIconByName("Plus");
private static UIElement GetIconByName(string name)
{
try
{
return Application.Current.FindResource(name) as UIElement;
}
catch
{
return null;
}
}
}
//STATIC CLASS TO WRITE TO THE CONSOLE TEXTBOX
public static class Console
{
public static void WriteLine(string message)
{
var console = ((MainWindow) Application.Current.MainWindow).Console;
if (console == null)
{
Debug.WriteLine(message);
return;
}
console.Text = $"{message}\n{console.Text}";
}
}
//STATIC EXTENSION CLASS FOR CHANGING COLORS
public static class Extensions
{
public static UIElement ToRed(this UIElement element)
{
if (element == null) return null;
var result = (UIElement)System.Windows.Markup.XamlReader.Parse(System.Windows.Markup.XamlWriter.Save(element));
result.ReColorAll(new SolidColorBrush(Colors.Red));
return result;
}
private static void ReColorAll(this DependencyObject element, Brush newColor)
{
if (element is null) return;
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
// Retrieve child visual at specified index value.
var childVisual = VisualTreeHelper.GetChild(element, i);
switch (childVisual)
{
case Shape shape:
{
if (shape.Fill != null) shape.Fill = newColor;
if (shape.Stroke != null) shape.Stroke = newColor;
break;
}
case GeometryDrawing drawing:
{
if (drawing.Brush != null) drawing.Brush = newColor;
break;
}
}
childVisual.ReColorAll(newColor);
}
}
}
Converter class
//CONVERTER CLASS TO CONVERTER ICONS TO RED
public class ToRedConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Console.WriteLine($"PARAMETER: {parameter} - VALUE: {value}");
var result = !(value is UIElement element) ? value : element.ToRed();
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
MainWindow.xaml
<Window x:Class="WpfAllPurposesTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:icon="clr-namespace:WpfAllPurposesTest"
Title="InfragisticsWindow" Width="700" Height="800">
<Window.Resources>
<icon:ToRedConverter x:Key="ToRed"/>
<!--STYLE/TEMPLATE FOR TOGGLE BUTTON-->
<Style x:Key="TreeToggleButtonStyle" TargetType="ToggleButton" x:Shared="False">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid Width="20" Height="20" Background="{TemplateBinding Background}">
<ContentControl x:Name="ExpandPath" Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--STYLE/TEMPLATE FOR TREEVIEWITEM-->
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowToHide" Height="20"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Name="BrdBackground" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" BorderBrush="Gray" BorderThickness="0,0,0,0"/>
<!--VERTICAL LINE-->
<Border Name="VerticalLine" Grid.Row="0" Grid.RowSpan="2" Grid.Column="0">
<Path Data="M 5 1 L 5 9" StrokeThickness="0.5" Stroke="Black" Stretch="Fill" VerticalAlignment="Stretch" HorizontalAlignment="Center"/>
</Border>
<!--HORIZONTAL LINE-->
<Border Grid.Row="0" Grid.Column="0" Width="25">
<Path Data="M 12 12 L 25 12" StrokeThickness="0.5" Stroke="Black" Stretch="None"/>
</Border>
<!--EXPANDER / PLUS / MINUS ICON-->
<ToggleButton x:Name="Expander" Grid.Column="0" Grid.Row="0" Background="White" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
ClickMode="Press" Content="{Binding Source={StaticResource Plus}}" Style="{DynamicResource TreeToggleButtonStyle}" Visibility="Visible" Margin="0,0,2,0"/>
<!--TREE VIEW ITEM-->
<ContentPresenter x:Name="PART_Header" Grid.Column="1" Grid.Row="0" ContentSource="Header" HorizontalAlignment="Left"/>
<!--TREE VIEW ITEM CHILDREN HOST-->
<ItemsPresenter x:Name="ItemsHost" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" />
<!--DUMMY BORDER TO MAKE ITEM AVAILABLE FOR MOUSE OVER AND SELECTION-->
<Border x:Name="TopBorder" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderThickness="0" Background="Transparent"/>
</Grid>
<!--TRIGGERS-->
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="Expander" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="IsExpanded" Value="false">
<Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="TopBorder" Property="IsMouseOver" Value="true"/>
<Condition Property="IsSelected" Value="false"/>
<Condition Property="IsExpanded" Value="false"/>
</MultiTrigger.Conditions>
<Setter TargetName="Expander" Property="Content" Value="{Binding Source={StaticResource Plus}, Converter={StaticResource ToRed}, ConverterParameter=CONVERTtview1}"/>
<Setter TargetName="Expander" Property="Background" Value="LightSkyBlue"/>
<Setter TargetName="BrdBackground" Property="Background" Value="LightSkyBlue"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition SourceName="TopBorder" Property="IsMouseOver" Value="true"/>
<Condition Property="IsSelected" Value="false"/>
<Condition Property="IsExpanded" Value="true"/>
</MultiTrigger.Conditions>
<Setter TargetName="Expander" Property="Content" Value="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}, ConverterParameter=CONVERTtview2}"/>
<Setter TargetName="Expander" Property="Background" Value="LightSkyBlue"/>
<Setter TargetName="BrdBackground" Property="Background" Value="LightSkyBlue"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--STYLE/TEMPLATE FOR BUTTON-->
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<ContentControl Name="Temp_Content" Width="50" Height="50" Content="{StaticResource Plus}"/>
<ContentPresenter />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Temp_Content" Property="Content" Value="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}, ConverterParameter=CONVERTbtn}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<ContentControl Content="{DynamicResource Plus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{DynamicResource Minus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Plus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Minus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Plus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={StaticResource Minus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<ContentControl Content="{x:Static icon:Icons.Plus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{x:Static icon:Icons.Minus}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Plus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
<ContentControl Content="{Binding Source={x:Static icon:Icons.Minus}, Converter={StaticResource ToRed}}" Width="50" Height="50" Margin="10"/>
</StackPanel>
<TreeView Grid.Row="2" Grid.Column="0" Width="200">
<TreeViewItem Header="Parent 1">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 2">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 3">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 4">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
<TreeViewItem Header="Parent 5">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
<TreeViewItem Header="Child 3"/>
<TreeViewItem Header="Child 4"/>
</TreeViewItem>
</TreeView>
<StackPanel Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center">
<Button Content="Test"/>
<Button Content="Test 1"/>
</StackPanel>
<TextBox x:Name="Console" Grid.Row="2" Grid.Column="2" IsReadOnly="True"/>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow
{
public MainWindow()
{
Application.Current.Resources.MergedDictionaries.Add(
Application.LoadComponent(new Uri("WpfAllPurposesTest;component/MyResources.xaml", UriKind.Relative)
) as ResourceDictionary);
InitializeComponent();
}
}
UPDATE: While I was writing this question, I realized that this issue somehow is time dependent ?!?
If I immediately use the triggers somehow they work, but waiting a couple of seconds they don't
In the below example I waited a couple of second (finding shortcuts for recording):
When pointing at the TreeViewItem
s and the Background
turns blue, the icon disappears. Also the buttons in the middle does not have the icon from the trigger.
On the right side is the message from the Converter shown, and it shows that the correct trigger is triggered but the converter does not get the value.
In the below example, I was a little bit quicker with the recording short-cut:
In this example, the parent tree view items are shown correctly and icon is also changing, the message from converter shows also that the value is not null.
however for the second trigger which is triggered a little bit later and for the buttons it doesn't work.
Does any one know why this is happening or how to solve it ?
UPDATE
To remove all unnecessary focus and confusion.
This question is about the part:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter ... Value="{Binding Source={StaticResource PlusRed}}"/>
</Trigger>
</ControlTemplate.Triggers>
In a ControlTemplate.Trigger
when using the Setter
with {Binding Source={StaticResource...
It only reads the StaticResource
for a brief moment after the compiling, if you wait a couple of seconds. it will not read it.
I removed all of the converters and the issue is still there...
Conclusion:
After some comments, the following comment of @BionicCode cleared the confusion.
The binding you are referring to is static. Binding is intended to bind to a value that can change. Binding will update the target of the source raiders a PropertyChanged event. Binding is not meant to set a referenced to an object. You use StaticResource for this purpose (see my answer)
In order to use the Converter I was creating a binding to a StaticResource which of course was not the intention.
You are doing it completely wrong and too expensive when it comes to performance. Also your styles contain redundant elements like the "TopBorder"
in your TreeViewItem
template and wrong trigger logic.
The proper way would be to define all resources in a XAML ResourceDictionary
and reference them using the StaticResource
markup. Don't use x:Static
in this context.
Your algorithm to make elements red or change their color in general is very inefficient. For example you should not traverse the visual tree of the icon to change the Background
of each element - even based on element type (which requires to implement a smelly type switch). Your current algorithm even requires XAML element de-/serialization. In other words, the overall performance is bad, which is totally unnecessary at this point.
You can replace this logic alongside the converter and simplify it by using data binding properly. This will also improve the performance.
I assume the desired behavior for the TreeViewItem
expander is
LightSkyBlue
Red
When implementing triggers, you must give the templated element a default state.
Since the default of a boolean variable and therefore for the ToggleButton.IsChecked
property of the expander is false
, you should design the template based on the collapsed state. Then define triggers to change the appearance of elements when the state changes to expanded. This reduces the number of triggers and improves readability.
Define your icons to allow dynamic coloring i.e. fill and stroke. This way we enable to set those attributes via data binding.
The following example expects the drawings to be hosted in a ContentControl
(or a derived type like a Button
). It uses the ContentControl.Background
to color the icon's background (in this case the Canvas.Background
) and the ContentControl.Foreground
to color the strokes of the actual icon drawings.
To achieve this behavior we use Bindig.RelativeSource
to bind to the ContentControl
(the parent that will be added later in a different scope):
<Viewbox x:Key="MinusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}"
Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" /> <!-- Static border color (gray) -->
<Rectangle Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}"
Width="9"
Height="2"
Canvas.Left="11.5"
Canvas.Top="15"
Stretch="Fill" />
</Canvas>
</Viewbox>
<Viewbox x:Key="PlusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}"
Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" /> <!-- Static border color (gray) -->
<Path Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}"
Width="9"
Height="9"
Canvas.Left="11.5"
Canvas.Top="11.5"
Stretch="Fill"
Data="F1 M 20.5,15L 17,15L 17,11.5L 15,11.5L 15,15L 11.5,15L 11.5,17L 15,17L 15,20.5L 17,20.5L 17,17L 20.5,17L 20.5,15 Z " />
</Canvas>
</Viewbox>
When you want to use the dynamic icons, you can host them in any ContentControl
. You use StaticResource
markup to reference the icon resources. And you reference it directly (without a Binding
to the resource). For example
<Button Content="{StaticResource PlusIcon}" />
Again, you define a default state (in case of a button this is not-clicked) and define triggers that modify the element when the state changes. It is highly recommended to use the VisualStateManager
instead of triggers.
To keep the answer technically as simple as possible, the following example uses triggers. They change the coloring of the icon and the icon itself (as of your requirement):
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<ContentControl x:Name="IconHost"
Foreground="LightSkyBlue"
Background="Transparent"
Content="{StaticResource PlusIcon}"
Width="50"
Height="50" />
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="IconHost"
Property="Content"
Value="{StaticResource MinusIcon}" />
<Setter TargetName="IconHost"
Property="Foreground"
Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ToggleButton
of TreeViewItem
You use the icons like in Step 2, by hosting them in a ContentControl
.
The following snippet shows how to use the icon with the expander ToggleButton
. You can move the setting of the ToggleButton.Content
to a Style
:
<ToggleButton x:Name="Expander"
Grid.Column="0"
Grid.Row="0"
Content="{StaticResource PlusIcon}"
Background="{TemplateBinding Background}"
Foreground="LightSkyBlue"
IsChecked="{TemplateBinding IsExpanded}"
ClickMode="Press"
Style="{DynamicResource TreeToggleButtonStyle}"
Visibility="Visible"
Margin="0,0,2,0" /> <!-- Consider to use {StaticResource TreeToggleButtonStyle} when possible -->
The following example is an improved version of your TreeViewItem
style. It fixes the incorrect trigger logic and highlight behavior.
The complete logic is implemented completely in XAML. It uses the in Step 1
defined dynamic icons and data binding to make the binding converter and extension methods obsolete.
The layout is improved, for example the redundant "TopBorder"
is removed and all elements bind to the templated parent's TreeViewItem.Background
property to fetch the current background highlight color (to reduce trigger setters).
Then the complete template is now based on the default state, which is the collapsed tree node. All attributes like Visibility
and Background
are configured accordingly.
The complete TreeViewItem
style could look as follows:
<Window>
<Window.Resources>
<!-- Minus icon -->
<Viewbox x:Key="MinusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0"
Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" />
<Rectangle Width="9"
Height="2"
Canvas.Left="11.5"
Canvas.Top="15"
Stretch="Fill"
Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}" />
</Canvas>
</Viewbox>
<!-- Plus icon -->
<Viewbox x:Key="PlusIcon"
x:Shared="False"
Stretch="Uniform">
<Canvas Width="32"
Height="32"
Clip="F1 M 0,0L 32,0L 32,32L 0,32L 0,0"
Background="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Background}">
<Rectangle Width="19"
Height="19"
Canvas.Left="6.49999"
Canvas.Top="6.5"
Stretch="Fill"
StrokeMiterLimit="2.75"
Stroke="#FF575756" />
<Path Width="9"
Height="9"
Canvas.Left="11.5"
Canvas.Top="11.5"
Stretch="Fill"
Fill="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=Foreground}"
Data="F1 M 20.5,15L 17,15L 17,11.5L 15,11.5L 15,15L 11.5,15L 11.5,17L 15,17L 15,20.5L 17,20.5L 17,17L 20.5,17L 20.5,15 Z " />
</Canvas>
</Viewbox>
<!-- Button style -->
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<StackPanel>
<ContentControl x:Name="IconHost"
Width="50"
Height="50"
Foreground="LightSkyBlue"
Background="Transparent"
Content="{StaticResource Plus}" />
<ContentPresenter />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="IconHost"
Property="Content"
Value="{StaticResource Minus}" />
<Setter TargetName="IconHost"
Property="Foreground"
Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<TreeView>
<!-- TreeViewItem style -->
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter Property="Background"
Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowToHide"
Height="20" />
<RowDefinition />
</Grid.RowDefinitions>
<Border Name="BrdBackground"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Background="{TemplateBinding Background}"
BorderBrush="Gray"
BorderThickness="0,0,0,0" />
<!--VERTICAL LINE-->
<Border Name="VerticalLine"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0">
<Path Data="M 5 1 L 5 9"
StrokeThickness="0.5"
Stroke="Black"
Stretch="Fill"
VerticalAlignment="Stretch"
HorizontalAlignment="Center" />
</Border>
<!--HORIZONTAL LINE-->
<Border Grid.Row="0"
Grid.Column="0"
Width="25">
<Path Data="M 12 12 L 25 12"
StrokeThickness="0.5"
Stroke="Black"
Stretch="None" />
</Border>
<!--EXPANDER / PLUS / MINUS ICON-->
<ToggleButton x:Name="Expander"
Grid.Column="0"
Grid.Row="0"
Content="{StaticResource PlusIcon}"
Background="{TemplateBinding Background}"
Foreground="LightSkyBlue"
IsChecked="{TemplateBinding IsExpanded}"
ClickMode="Press"
Style="{DynamicResource TreeToggleButtonStyle}"
Visibility="Visible"
Margin="0,0,2,0" /> <!-- Consider to use {StaticResource TreeToggleButtonStyle} when possible (to improve performance) -->
<!--TREE VIEW ITEM HEADER -->
<ContentPresenter x:Name="PART_Header"
Grid.Column="1"
Grid.Row="0"
ContentSource="Header"
HorizontalAlignment="Left" />
<!--TREE VIEW ITEM CHILDREN HOST-->
<ItemsPresenter x:Name="ItemsHost"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
Visibility="Collapsed" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems"
Value="false">
<Setter TargetName="Expander"
Property="Visibility"
Value="Collapsed" />
</Trigger>
<Trigger Property="IsExpanded"
Value="True">
<Setter TargetName="ItemsHost"
Property="Visibility"
Value="Visible" />
<Setter TargetName="Expander"
Property="Content"
Value="{StaticResource MinusIcon}" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="LightSkyBlue" />
<Setter TargetName="Expander"
Property="Foreground"
Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Window>