0
votes

I have the following piece of XAML that creates a treeview and populates it with TreeViewItems. The Converter simply takes the name and spits back a StackPanel with 2 different coloured strings. The only way I've found that I can actually use that stackpanel visually is by setting it in the header of a TreeViewItem, this however doesn't work optimally as a TreeViewItem is created programatically already.

The result is that I can't click the label(header) but it looks fancy, however I discovered that there's a big space in front of the label that I can click, which must then be from the generated TreeViewItem. I really need the label to contain a stackpanel of 2 textblocks, is there a solution for this?

<UserControl.Resources>
        <XmlDataProvider x:Key="MyXmlProvider" Source="LogansTest.xml" XPath="/Items"/>
        <customScripts:NameGeneration x:Key="NameGeneration"/>
        <HierarchicalDataTemplate x:Key="NodeTemplate" ItemsSource="{Binding XPath=./*}">
            <TreeViewItem x:Name="nodetext"/>

            <HierarchicalDataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
                    <Setter TargetName="nodetext" Property="Header" Value="{Binding Converter={StaticResource NameGeneration}}"/>
                </DataTrigger>
            </HierarchicalDataTemplate.Triggers>
        </HierarchicalDataTemplate>
    </UserControl.Resources>

EDIT

Following mm8's suggestion I've edited my code, I've uploaded my XAML in its entirety, it is no longer generating the tree, I'm pretty new to XAML so I can't see what I'm doing wrong, heh. Ran a few tests, the converter isn't being called and the treeview is just empty where before it had all the nodes of the XML file

<UserControl x:Class="XmlOutline.OutlineWindowControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
             xmlns:customScripts="clr-namespace:XmlOutline.CustomScripts"
             Background="{DynamicResource {x:Static vsshell:VsBrushes.WindowKey}}"
             Foreground="{DynamicResource {x:Static vsshell:VsBrushes.WindowTextKey}}"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300"
             Name="MyToolWindow">
    <UserControl.Resources>
        <XmlDataProvider x:Key="MyXmlProvider" Source="LogansTest.xml" XPath="/Items"/>
        <customScripts:NameGeneration x:Key="NameGeneration"/>
    </UserControl.Resources>


    <Grid x:Name="TreeGrid" DataContext="MyXmlProvider">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TreeView Name="TreeItems" Visibility="Hidden"
                  ItemsSource="{Binding Source={StaticResource MyXmlProvider}}"
                  HorizontalAlignment="Stretch"
                  VerticalAlignment="Stretch"
                  VirtualizingStackPanel.IsVirtualizing="False"
                  VirtualizingStackPanel.VirtualizationMode="Standard"
                  Background="#252525"
                  SelectedItemChanged="TreeView_OnSelectedItemChanged">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding XPath=./*}"/>
            </TreeView.ItemTemplate>
            <TreeView.ItemContainerStyle>
                <Style TargetType="TreeViewItem">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
                            <Setter Property="Header" Value="{Binding Converter={StaticResource NameGeneration}}"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
        </TreeView>
    </Grid>
</UserControl>

EDIT This is the code that sets the new datasource whenever a new XML document is opened.

var provider = new XmlDataProvider()
{
    Source = new Uri(gotFocus.Document.Path + gotFocus.Document.Name),
    XPath = "./*"
};

OutlineWindowInstance.TreeItems.DataContext = provider;

By the way, the entire GIT repo can be found here: https://github.com/LoganLabster/VsXmlOutline

2
I'm aware that there's a very similar question out there stackoverflow.com/questions/48626453/… But it's asking for a very different solution which isn't applicable in my situation! :) - TheLogan
I've discovered that if I set the ItemSource to just Binding, it will iterate over the nodes and create the treeviewitems, it will also run the converter (so that line works too), but it will not assign the text value to the header. - TheLogan

2 Answers

1
votes

You are not supposed to create another TreeViewItem container in an HierarchicalDataTemplate. Try to define an ItemContainerStyle that sets the Header property:

<TreeView ItemsSource="{Binding Source={StaticResource MyXmlProvider}}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding XPath=./*}" />
    </TreeView.ItemTemplate>
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
                    <Setter Property="Header" Value="{Binding Converter={StaticResource NameGeneration}}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>
0
votes

Thanks to @mm8 I managed to find the answer, it was really quite simple once I figured it out (which took way too long, doh). Rather than set the StackPanel to the treeviewitem header, I built the StackPanel in XAML and set the values there one at a time, and voila, it worked.

<UserControl x:Class="XmlOutline.OutlineWindowControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:vsshell="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.15.0"
             xmlns:customScripts="clr-namespace:XmlOutline.CustomScripts"
             Background="{DynamicResource {x:Static vsshell:VsBrushes.WindowKey}}"
             Foreground="{DynamicResource {x:Static vsshell:VsBrushes.WindowTextKey}}"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300"
             Name="MyToolWindow">
    <UserControl.Resources>
        <XmlDataProvider x:Key="MyXmlProvider" Source="LogansTest.xml" XPath="/Items"/>
        <customScripts:NameGeneration x:Key="NameGeneration"/>
    </UserControl.Resources>

    <Grid x:Name="TreeGrid" DataContext="MyXmlProvider">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TreeView Name="TreeItems" Visibility="Hidden"
                  ItemsSource="{Binding}"
                  HorizontalAlignment="Stretch"
                  VerticalAlignment="Stretch"
                  VirtualizingStackPanel.IsVirtualizing="False"
                  VirtualizingStackPanel.VirtualizationMode="Standard"
                  Background="#252525"
                  SelectedItemChanged="TreeView_OnSelectedItemChanged"
                  TreeViewItem.Expanded="TreeViewItem_Expanded"
                  TreeViewItem.Collapsed="TreeViewItem_Collapsed">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate x:Name="myTest" ItemsSource="{Binding XPath=./*}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock x:Name="Title"    Foreground="LightSkyBlue" FontSize="14"/>
                        <TextBlock x:Name="SubTitle" Foreground="YellowGreen"  FontSize="13"/>
                    </StackPanel>
                    <HierarchicalDataTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
                            <Setter TargetName="Title" Property="Text"  Value="{Binding Path=Name}"/>
                            <Setter TargetName="SubTitle" Property="Text" Value="{Binding Converter={StaticResource NameGeneration}}" />
                        </DataTrigger>
                    </HierarchicalDataTemplate.Triggers>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</UserControl>