views:

26

answers:

1

So I am having an issue with the TreeView. If I build a tree view statically, every node in the tree is selectable in that when I click on it, it highlights itself blue, indicating that node is selected.

<TreeView 
    Grid.Column="0"
    Grid.Row="2"
    MinHeight="100" 
    MinWidth="100"
    BorderBrush="White"
    DataContext="{Binding Projects, Source={x:Static SizingApp:Manager.Instance}}">
<TreeViewItem Header="Project 1" IsExpanded="True">
    <TreeViewItem Header="Step 1" IsExpanded="True">
        <TreeViewItem Header="Load 1" IsExpanded="True"></TreeViewItem>
        <TreeViewItem Header="Load 2" IsExpanded="True"></TreeViewItem>
    </TreeViewItem>
    <TreeViewItem Header="Step 2" IsExpanded="True">
        <TreeViewItem Header="Load 1" IsExpanded="True"></TreeViewItem>
        <TreeViewItem Header="Load 2" IsExpanded="True"></TreeViewItem>
    </TreeViewItem>
</TreeViewItem>

However, I am Binding to the TreeView to populate it. Furthermore, I am binding to objects that implement Emiel Jongerius's BindableObjectBase3 class. This is a wonderful base class implementation that allows my objects to be Bindable and implement the INotifyPropertyChanged interface with the concern for manual DependencyProperty management.

So this is the basic class structure (simplified from my actual objects) that I am trying to implement in a TreeView.

    public abstract class MyCustomClass : BindableObjectBase3
{
    private string m_strName;

    public virtual string Name
    {
        get
        {
            using (this.GetPropertyTracker(() => this.Name))
            {
                return m_strName;
            }
        }
        set
        {
            this.SetValue(ref this.m_strName, value, () => this.Name);
        }
    }
}

public class Project : MyCustomClass
{
    private List<Step> m_steps;

    public List<Step> Steps
    {
        get
        {
            using (this.GetPropertyTracker(() => this.Steps))
            {
                return m_steps;
            }
        }
        set
        {
            this.SetValue(ref this.m_steps, value, () => this.Steps);
        }
    }
}

public class Step : MyCustomClass
{
    private List<Load> m_loads;

    public List<Load> Loads
    {
        get
        {
            using (this.GetPropertyTracker(() => this.Loads))
            {
                return m_loads;
            }
        }
        set
        {
            this.SetValue(ref this.m_loads, value, () => this.Steps);
        }
    }
}

public class Load : MyCustomClass
{
}

And this is the basic XAML I use to implement the TreeView:

<TreeView 
    Grid.Column="0"
    Grid.Row="2"
    MinHeight="100" 
    MinWidth="100"
    BorderBrush="White"
    DataContext="{Binding Projects, Source={x:Static SizingApp:Manager.Instance}}">
    <TreeView.Resources>
        <HierarchicalDataTemplate x:Key="LoadTemplate">
            <TreeViewItem Header="{Binding Path=Name}">
            </TreeViewItem>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="StepTemplate">
            <TreeViewItem Header="{Binding Path=Name}" IsExpanded="True"
                    ItemsSource="{Binding Path=Loads}"
                    ItemTemplate="{StaticResource LoadTemplate}">
            </TreeViewItem>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="ProjectTemplate">
            <TreeViewItem Header="{Binding Path=Name}" IsExpanded="True"
                    ItemsSource="{Binding Path=Steps}"
                    ItemTemplate="{StaticResource StepTemplate}">
            </TreeViewItem>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
    <TreeViewItem 
            Header="{Resx ResxName=PSSPECApplication.Controls.ProjectControlResources, Key=projectTree_Header}"
            ItemsSource="{Binding}"
            IsExpanded="True"
            Focusable="True"
            ItemTemplate="{StaticResource ProjectTemplate}">
    </TreeViewItem>
</TreeView>

Now all of this works fine as far as binding goes. I can bind to an ObservableCollection<Project> and as I add/remove/manipulate projects, the TreeView updates accordingly.

However, the only node in the TreeView that seems selectable is the first node (the one that is static). All of the other nodes create through dynamic Binding do not indicate that they are selected on the GUI. I would expect that they would also highlight blue when clicked on. But instead they do nothing. Does anyone have an idea of why?

+1  A: 

You shouldn't be defining TreeViewItems explicitly in your ItemTemplates. The reason you can't select any of the items is that they have no parent TreeView to control selection behavior. You need to let the TreeView generate the TreeViewItem controls for you and only use the item templates to define the UI for the Headers and the bindings for their items. Use something like this instead:

<Window.Resources>
    <HierarchicalDataTemplate x:Key="LoadTemplate">
        <TextBlock Text="{Binding Path=Name}"/>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate x:Key="StepTemplate" ItemsSource="{Binding Loads}" ItemTemplate="{StaticResource LoadTemplate}">
        <TextBlock Text="{Binding Path=Name}"/>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate x:Key="ProjectTemplate" ItemsSource="{Binding Steps}" ItemTemplate="{StaticResource StepTemplate}">
        <TextBlock Text="{Binding Path=Name}"/>
    </HierarchicalDataTemplate>
</Window.Resources>

<TreeView MinHeight="100" MinWidth="100" BorderBrush="White"
          ItemsSource="{Binding Path=Projects}"
          ItemTemplate="{StaticResource ProjectTemplate}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="True" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>
John Bowen
Thank you very much. So much of figuring out this control seems to non-intuitive. I'm happy you could share your experience. Thanks.
Ristogod