Action Heinz Action Heinz - 1 year ago 575
C# Question

How to bind expanded event of WPF treeview item to the viewmodel

I'm trying to bind the expanded event to the viewmodel (not the *.xaml.cs file) to extend the treeview only after expanding a node.

My approach is:

<TreeView x:Name="TreeViewTest" ItemsSource="{Binding Items}">
<HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=OneTime}">
<Label Content="{Binding Title, Mode=OneTime}" />
<i:EventTrigger EventName="TreeViewItem.Expanded">
<i:InvokeCommandAction Command="{Binding DataContext.ExpandedCommand, Source={x:Reference TreeViewTest}}"> </i:InvokeCommandAction>

I get following error message:

Cannot call MarkupExtension.ProvideValue because of a cyclical dependency. Properties inside a MarkupExtension cannot reference objects that reference the result of the MarkupExtension. The affected MarkupExtensions are:

Can someone help me how to solve this error or is there another way to bind the event to a command in the viewmodel?

Answer Source

As I can understand you try to attach a command to TreeViewItem.Expanded event. I've done a small research concerning this issue and here is the result I've end up with.

  1. There is a small problem with the tree view items and this event.
  2. There are several approaches to solve the problem:

First is AttachedProperties in style of the TreeViewItem, here is the link: Invoke Command when TreeViewItem is Expanded

Second is Behavior involved solution:

  1. XAML:

    <TreeView x:Name="TreeViewTest" ItemsSource="{Binding Items}" TreeViewItem.Expanded="TreeViewTest_OnExpanded">
            <HierarchicalDataTemplate DataType="{x:Type soTreeViewHelpAttempt:TreeObject}" 
                                      ItemsSource="{Binding Children, Mode=OneTime}">
                            <Label Content="{Binding }" />
                    <Label Content="{Binding Title, Mode=OneTime}" />
            <soTreeViewHelpAttempt:TreeViewItemExpandBehavior OnExpandedAction="{Binding OnExpandedActionInViewModel}"/>
  2. ViewModel:

        public MainDataContext()
        OnExpandedActionInViewModel = new Action<object, RoutedEventArgs>(OnExpanded);
    public Action<object, RoutedEventArgs> OnExpandedActionInViewModel
        get { return _onExpandedActionInViewModel; }
        private set
            _onExpandedActionInViewModel = value;
  3. Behavior Command property:

    public static readonly DependencyProperty OnExpandedActionProperty = DependencyProperty.Register(
        "OnExpandedAction", typeof (Action<object,RoutedEventArgs>), typeof (TreeViewItemExpandBehavior), new PropertyMetadata(default(Action<object,RoutedEventArgs>)));
    public Action<object,RoutedEventArgs> OnExpandedAction
        get { return (Action<object,RoutedEventArgs>) GetValue(OnExpandedActionProperty); }
        set { SetValue(OnExpandedActionProperty, value); }
  4. Behavior code:

        protected override void OnAttached()
        AssociatedObject.Loaded += AssociatedObjectOnLoaded;
    private void AssociatedObjectOnLoaded(object sender, RoutedEventArgs routedEventArgs)
        var treeView = sender as TreeView;
        if(treeView == null) return;
        treeView.ItemsSource.Cast<object>().ToList().ForEach(o =>
            var treeViewItem = treeView.ItemContainerGenerator.ContainerFromItem(o) as TreeViewItem;
            if(treeViewItem == null) return;
            treeViewItem.Expanded += TreeViewItemOnExpanded;
    private void TreeViewItemOnExpanded(object sender, RoutedEventArgs routedEventArgs)
        if(OnExpandedAction == null)
        OnExpandedAction(sender, routedEventArgs);
    protected override void OnDetaching()
        AssociatedObject.Loaded -= AssociatedObjectOnLoaded;
        _list.ForEach(item => item.Expanded -= TreeViewItemOnExpanded);

I hope It will help you. Regards,

Edit: fixed formatting

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download