开发者

Silverlight treeview: save expanded/collapsed state

I'm using a hierarchical tree view in Silverlight 4. This tree can be cleared and rebuilded quite often, depending on the user's actions. When this happends, the tree is collapsed by default, which can be annoying from a user perspective.

So, I want to somehow save which nodes are expanded so I can restore the visual state of my tree after it is clear and reloaded.

My treeview is implemented like this:

xmlns:controls="clr-namespace:System.Windows.Controls;a开发者_开发技巧ssembly=System.Windows.Controls"
xmlns:controls2="clr-namespace:System.Windows;assembly=System.Windows.Controls"

<controls:TreeView x:Name="Tree"
    ItemsSource="{Binding Source={StaticResource ViewModel}, Path=TreeStructure, Mode=OneWay}"
    ItemTemplate="{StaticResource hierarchicalTemplate}" />

<controls2:HierarchicalDataTemplate x:Key="hierarchicalTemplate" ItemsSource="{Binding Children}">
        <TextBlock Text="{Binding Value.DisplayName}">
</controls2:HierarchicalDataTemplate>

ItemsSource of my treeview is bound on an ObservableCollection TreeStructure;

Node is a wrapper class that looks like that:

public class Node
{
    public object Value { get; private set; }

    public ObservableCollection<Node> Children { get; private set; }

    public Node(object value)
    {
        Value = value;
        Children = new ObservableCollection<Node>();
    }
 }

Pretty standard stuff. I saw some solutions for WPF, but I can find anything for the Silverlight tree view...

Any suggestions?

Thanks!


Given the way you are implementing your data as a tree, why not bind the 'TreeViewItem.IsExpanded` dependency property to a bool property on your own Node?

It will need to be an INotifyPropertyChanged property at a minimum so Node will need to implement INotifyPropertyChanged.

In Silverlight 5 you can just set a style like this to bind to the IsExpanded property:

<Style TargetType="sdk:TreeViewItem" x:Key="itemStyle">
    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>

And use with

ItemContainerStyle="{Binding Source={StaticResource itemStyle}}"

In Silverlight 4 there are a number of workarounds.


Here's what I did to bind on the TreeViewItem.IsExpanded property. First, I added an IsExpanded property in my Node class.

public class Node : INotifyPropertyChanged
{
    public object Value { get; private set; }

    public ObservableCollection<Node> Children { get; private set; }

    private bool isExpanded;
    public bool IsExpanded
    {
        get
        {
            return this.isExpanded;
        }
        set
        {
            if (this.isExpanded != value)
            {
                this.isExpanded = value;
                NotifyPropertyChanged("IsExpanded");
            }
        }
    }

    public Node(object value)
    {
        Value = value;
        Children = new ObservableCollection<Node>();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
 }

After that, I subclassed the TreeView and TreeViewItem controls (I lose the custom theme on my treeview, but whatever...)

public class BindableTreeView : TreeView
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        var itm = new BindableTreeViewItem();
        itm.SetBinding(TreeViewItem.IsExpandedProperty, new Binding("IsExpanded") { Mode = BindingMode.TwoWay });

        return itm;
    }
}

public class BindableTreeViewItem : TreeViewItem
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        var itm = new BindableTreeViewItem();
        itm.SetBinding(TreeViewItem.IsExpandedProperty, new Binding("IsExpanded") { Mode = BindingMode.TwoWay });

        return itm;
    }
}

In my XAML, I just have to use BindableTreeView instead of TreeView, and it works.


The trick is to use SetterValueBindingHelper from here. Then your XAML will look like the following. Make sure you carefully copy what I have below.

<sdk:TreeView.ItemContainerStyle>
    <Style TargetType="sdk:TreeViewItem">
        <Setter Property="local:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <local:SetterValueBindingHelper>
                    <local:SetterValueBindingHelper Property="IsSelected" Binding="{Binding Mode=TwoWay, Path=IsSelected}"/>
                    <local:SetterValueBindingHelper Property="IsExpanded" Binding="{Binding Mode=TwoWay, Path=IsExpanded}"/>
                </local:SetterValueBindingHelper>
            </Setter.Value>
        </Setter>
    </Style>
</sdk:TreeView.ItemContainerStyle>

The syntax isn't exactly like what you would use in WPF, but it works and it works well!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜