4

I have a hierarchical data classes like

public class MyNode 
{
   public string Name { get; set;}
   public bool IsExpanded { get; set;}
   public List<MyNode> Nodes { get; set;}
}

I could define a HierarchicalDataTemplate to bind MyNode classes to the TreeView.

<sdk:TreeView ItemsSource="{Binding RootNodes}">
  <sdk:TreeView.ItemTemplate>
    <sdk:HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
      <TextBlock Text="{Binding Name}" />
    </sdk:HierarchicalDataTemplate>
  </sdk:TreeView.ItemTemplate>
</sdk:TreeView>

The question is how to data-bind IsExpanded property of TreeViewItem to corresponding MyNode.IsExpanded property, so I could persist this information.

Thank you in advance, Lex

skaffman
  • 398,947
  • 96
  • 818
  • 769
Lex Lavnikov
  • 1,239
  • 9
  • 18

3 Answers3

4

I'm not sure if this works in Silverlight or not, but in WPF you can bind to IsExpanded by using a style:

<sdk:TreeView ItemsSource="{Binding RootNodes}">
    <sdk:TreeView.Resources>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}" />
        </Style>
    </sdk:TreeView.Resources>
    <sdk:TreeView.ItemTemplate>
        <sdk:HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
            <TextBlock Text="{Binding Name}" />
        </sdk:HierarchicalDataTemplate>
    </sdk:TreeView.ItemTemplate>
</sdk:TreeView>
Andy
  • 30,088
  • 6
  • 78
  • 89
2

I had to cope with the same issue and I did the MVVM way.

First, you want to create a property that will represent whether the item is expanded or not in your view-model (that's mainly where MVVM helps you out).

In your node's view-model simply add something like Boolean IsNodeExpanded { get; set; }.
Warning: The above is just the interface! you must notify changes with INotifyPropertyChanged.PropertyChanged, otherwise it will not work!

Next you want to hook it up to your view and this is very similar to what Andy here suggested; use styles. However his markup wasn't enough for me (one reason is that it didn't work).
What you actually want to do is place the style in the tree-view's ItemContainerStyle.

<TreeView ...>
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded" Value="{Binding Path=IsNodeExpanded, Mode=TwoWay}" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

And this did work for me in my case.


Note 1: Save yourself a headache, and make sure the binding in the style above is a two-way binding as it is presented. I had a project some time ago when I had to re-do this, I forgot to make it a two-way, and even debugging didn't help.

Note 2: You should use MVVM for this function, I have tried to use code-behind for it because it seemed shorter (I'm lazy) and it turned out to be a long mess, and not just because it requires a recursive function, also because hidden items don't seem to exist until their parent is opened. It's not pleasant, and it may seem like a quick way to do it, but my experience made it much longer.

MasterMastic
  • 20,711
  • 12
  • 68
  • 90
1

It is possible, if we override TreeView & TreeViewItem classes like this:

public class ExTreeView : System.Windows.Controls.TreeView
{
  protected override DependencyObject GetContainerForItemOverride()
  {
    return new ExTreeViewItem();
  }
}

public class ExTreeViewItem : System.Windows.Controls.TreeViewItem { public ExTreeViewItem() { SetBinding(IsExpandedProperty, new Binding("IsExpanded") { Mode = BindingMode.TwoWay }); }

protected override DependencyObject GetContainerForItemOverride() { return new ExTreeViewItem(); } }

Then use ExTreeView instead of TreeView, it will automatically data bind to IsExpanded property of hierarchical data item.

Lex Lavnikov
  • 1,239
  • 9
  • 18