0

I have a wpf apllication based on MVVM software archhitecture. It consist of treeView and ListView. When a treeView Node is clicked, all the child nodes of that node are displayed in the listview. I am able to achieve this part.

But whent the user click an item from the listView, that particular item (which is a node in treeview) should get selected in the treeView. I dont know how to do this. Basically I want to bind property SelectedItem to listview selected item. but it seems like treeview selectedItem propeerty is readonly.

    <TreeView Name="tv" ItemsSource="{Binding ChildAndAttributes}" VerticalAlignment="Stretch" Margin="12,12,12,35">
        <TreeView.Resources>
            <DataTemplate DataType="{x:Type tvcc:NodeViewModel}">
                <TextBlock Text="{Binding Text}" />
            </DataTemplate>
            <DataTemplate DataType="{x:Type tvcc:NodeAttributeViewModel}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding AttributeName}"  />
                    <TextBlock Text="{Binding AttributeValue}" Padding="2,0,0,0" Foreground="Blue" />
                </StackPanel>
            </DataTemplate>
        </TreeView.Resources>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildAndAttributes}">
                <ContentControl Content="{Binding}" />
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
Abhishek Batra
  • 1,539
  • 1
  • 18
  • 45

2 Answers2

0

Here is some extension of tree https://stackoverflow.com/a/18265571/634219 that allows you to bind selecteditem of tree:

public class TreeViewEx : TreeView
{
    public TreeViewEx()
    {
        SelectedItemChanged += TreeViewEx_SelectedItemChanged;
    }

    void TreeViewEx_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        SelectedItem = e.NewValue;
    }

    #region SelectedItem

    /// <summary>
    /// Gets or Sets the SelectedItem possible Value of the TreeViewItem object.
    /// </summary>
    public new object SelectedItem
    {
        get { return GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public new static readonly DependencyProperty SelectedItemProperty =
        DependencyProperty.Register("SelectedItem", typeof(object), typeof(TreeViewEx), new PropertyMetadata(SelectedItemProperty_Changed));

    static void SelectedItemProperty_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var targetObject = dependencyObject as TreeViewEx;
        if (targetObject != null)
        {
            var tvi = targetObject.FindItemNode(targetObject.SelectedItem);
            if (tvi != null)
                tvi.IsSelected = true;
        }
    }
    #endregion SelectedItem

    public TreeViewItem FindItemNode(object item)
    {
        TreeViewItem node = null;
        foreach (object data in Items)
        {
            node = ItemContainerGenerator.ContainerFromItem(data) as TreeViewItem;
            if (node != null)
            {
                if (data == item)
                    break;
                node = FindItemNodeInChildren(node, item);
                if (node != null)
                    break;
            }
        }
        return node;
    }

    protected TreeViewItem FindItemNodeInChildren(TreeViewItem parent, object item)
    {
        TreeViewItem node = null;
        bool isExpanded = parent.IsExpanded;
        if (!isExpanded) //Can't find child container unless the parent node is Expanded once
        {
            parent.IsExpanded = true;
            parent.UpdateLayout();
        }
        foreach (object data in parent.Items)
        {
            node = parent.ItemContainerGenerator.ContainerFromItem(data) as TreeViewItem;
            if (data == item && node != null)
                break;
            node = FindItemNodeInChildren(node, item);
            if (node != null)
                break;
        }
        if (node == null && parent.IsExpanded != isExpanded)
            parent.IsExpanded = isExpanded;
        if (node != null)
            parent.IsExpanded = true;
        return node;
    }
} 
Community
  • 1
  • 1
Jack Malkovich
  • 786
  • 13
  • 33
0

One of the easiest ways to select a TreeViewItem in a TreeView is to data bind to the TreeViewItem.IsSelected Property. This does mean that you'll have to add an extra bool IsSelected property to your data type class, but it will then enable you to select any item from the view model. You can data bind to this property in a Style:

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

Optionally, you might also want to data bind to the TreeViewItem.IsExpanded Property too, so that you can select and expand the relevant item from the view model:

YourDataType item = Items.First(i => i.Id == someValue);
item.IsSelected = true;
item.IsExpanded = true;
Sheridan
  • 68,826
  • 24
  • 143
  • 183