I have a TreeView component, and it can contain several types of nodes. Its all working well except I have multiple hierarchical data templates which differ just in the glyph image they display, DataType and ItemsSource but everything else is exactly the same.
I was wondering, is it possible to create just one ControlTemplate for all hierarchical data template and just modify the icon image by using the tag property?
So for example I have basic TreeNode class and nodes like, PersonNode, PropertyNode, StreetNode which inherit from TreeNode. TreeNode displays a folder icon, PersonNode displays a user icon, PropertyNode displays house icon and StreeNode displays street icon. So, actually they all have same content structure except, the icon, DataType and ItemsSource are changing.
How can I simplify my hierarchical data templates?
Sample code:
<HierarchicalDataTemplate
DataType="{x:Type MyTreeFolder:TreeNode}"
ItemsSource="{Binding Path=Items}">
<StackPanel Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSpecialNode}" Value="True">
<Setter Property="Background" Value="Blue"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<glyphs:GlyphAwesome
FontSize="12"
Glyph="folder"
Margin="0, 0, 4, 0"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding}" VerticalAlignment="Center"/>
</StackPanel>
</HierarchicalDataTemplate>
You could create a value converter that checks the type of the tree node and returns the glyph text. The type to glyph text mapping could be stored in a dictionary.
public class ObjectTypeToGlyphConverter : IValueConverter
{
private static readonly IDictionary<Type, string> TypeToGlyphMapping = new Dictionary<Type, string>
{
[typeof(TreeNode)] = "folder",
[typeof(PersonNode)] = "person",
[typeof(PropertyNode)] = "property"
};
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var type = value?.GetType();
return type != null && TypeToGlyphMapping.TryGetValue(type, out var glyph) ? glyph : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new InvalidOperationException();
}
}
You would need to create an instance of this converter in a resource dictionary in scope, e.g.:
<TreeView ItemsSource="{Binding TreeNodes}">
<TreeView.Resources>
<local:ObjectTypeToGlyphConverter x:Key="ObjectTypeToGlyphConverter"/>
</TreeView.Resources>
<!-- ...tree view definitions. -->
</TreeView>
Then you could use it in your hierarchical data template's GlyphAwesome
like this.
<glyphs:GlyphAwesome FontSize="12"
Glyph="{Binding Converter={StaticResource ObjectTypeToGlyphConverter}}"
Margin="0, 0, 4, 0"
VerticalAlignment="Center"/>
In this case you would only need one data template for the type TreeNode
, given that as you say all node types are essentially the same and there is no special handling for them except for the icon.