Get SelectedItem from TreeView?

26,111

Solution 1

Ok I know this is an old question and probably dead but as Charlie has it right. This is something that can also be used in code. You could do for example:

<ContentPresenter Content="{Binding ElementName=treeView1, Path=SelectedItem}" />

Which will show the selected item. You can add a style or DataTemplate to that or use a default DataTemplate to the object you are trying to show.

Solution 2

Step 1 Install the NuGet: Install-Package System.Windows.Interactivity.WPF

Step 2 In your Window tag add: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

Step 3 In the TreeView add:

    <TreeView Name="treeView1" ... >
         <i:Interaction.Triggers>
              <i:EventTrigger EventName="SelectedItemChanged">
                   <i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}" CommandParameter="{Binding ElementName=treeView1, Path=SelectedItem}"/>
              </i:EventTrigger>
          </i:Interaction.Triggers>
   ...
   </TreeView>

Step 4 In your ViewModel add:

        private ICommand _selectedItemChangedCommand;
        public ICommand SelectedItemChangedCommand
        {
            get
            {
                if (_selectedItemChangedCommand == null)
                    _selectedItemChangedCommand = new RelayCommand(args => SelectedItemChanged(args));
                return _selectedItemChangedCommand;
            }
        }

        private void SelectedItemChanged(object args)
        {
            //Cast your object
        }

Solution 3

Diego Torres's answer is clean and simple! But for those who don't want to install a NuGet Package just for this purpose, you can create your own dependency property that Execute Command when a even is fired.

namespace View.Helper
{
    public class EventToCommandAdaptor
    {
        public static readonly DependencyProperty TreeViewSelectedItemChangedCommand_DpProp =
            DependencyProperty.RegisterAttached(
              "TreeViewSelectedItemChangedCommand",
              typeof(ICommand),
              typeof(EventToCommandAdaptor), // owner type
              new PropertyMetadata(new PropertyChangedCallback(AttachOrRemoveTreeViewSelectedItemChangedEvent))
              );

        public static ICommand GetTreeViewSelectedItemChangedCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(TreeViewSelectedItemChangedCommand_DpProp);
        }

        public static void SetTreeViewSelectedItemChangedCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(TreeViewSelectedItemChangedCommand_DpProp, value);
        }

        public static void AttachOrRemoveTreeViewSelectedItemChangedEvent(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            TreeView treeview = obj as TreeView;
            if (treeview != null)
            {
                ICommand cmd = (ICommand)args.NewValue;

                if (args.OldValue == null && args.NewValue != null)
                {
                    treeview.SelectedItemChanged += ExecuteTreeViewSelectedItemChanged;
                }
                else if (args.OldValue != null && args.NewValue == null)
                {
                    treeview.SelectedItemChanged -= ExecuteTreeViewSelectedItemChanged;
                }
            }
        }

        private static void ExecuteTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> args)
        {
            DependencyObject obj = sender as DependencyObject;
            ICommand cmd = (ICommand)obj.GetValue(TreeViewSelectedItemChangedCommand_DpProp);

            if (cmd != null)
            {
                if (cmd.CanExecute(args.NewValue))
                {
                    cmd.Execute(args.NewValue);
                }
            }
        }
    }
}

Include xmlns:vh="clr-namespace:View.Helper" in <Windows></Windows>

And the TreeView looks like:

<TreeView ItemsSource="{Binding MyItemSource}"
    vh:EventToCommandAdaptor.TreeViewSelectedItemChangedCommand="{Binding MyCommand}">
</TreeView>

I learnt this trick when I encountered a similar situation: I want to execute a command when DataGrid.MouseDoubleClick Event is fired. But sorry that I forgot to mark down the source.

Solution 4

Maybe I've misunderstood your question but,

treeView1.SelectedItem

Should work.

Share:
26,111
TastyEquation60
Author by

TastyEquation60

Head of Product at divio.com, the company behind Aldryn and backers of django-CMS.

Updated on November 03, 2020

Comments

  • TastyEquation60
    TastyEquation60 over 3 years

    Does anyone know how I can get the SelectedItem (not the Header) from a TreeView?
    Here is my code:

    <TreeView Name="treeView1" DataContext="{Binding Path=PresentationsViewModel}" Grid.Column="1" >
        <TreeViewItem IsExpanded="True" Header="Objects-A-List" DisplayMemberPath="Name" ItemsSource="{Binding Path=MyItem.ListA}"></TreeViewItem>
        <TreeViewItem IsExpanded="True" Header="Objects-B-List" DisplayMemberPath="Name" ItemsSource="{Binding Path=MyItem.ListB}"></TreeViewItem>
        <TreeViewItem IsExpanded="True" Header="Objects-C-List" DisplayMemberPath="Name" ItemsSource="{Binding Path=MyItem.ListC}"></TreeViewItem>
    </TreeView>
    

    Note that there are 3 different Lists, containing 3 different Object-Types. It'd help me a lot to have something like:

    public Object SelectedObject
    {
        set { _selectedObject = value; RunMyMethod(); RaisePropertyChanged("SelectedObject"); }
    }  
    
  • TastyEquation60
    TastyEquation60 over 14 years
    I'm trying to do this without any Code-Behind, just via <TreeView Name="treeView1" DataContext="{Binding Path=PresentationsViewModel}" Grid.Column="1" SelectedItem="{Binding Path=MySelectedObject}"> Unfortunately TreeView doesn't have this (but ListView for example does have one)
  • Bob Horn
    Bob Horn over 12 years
    How can your a view model get this information? I get that ContentPresenter holds the selected item, but how do we get that over to the view model?
  • Ingó Vals
    Ingó Vals about 12 years
    @ Bob I guess you could bind the SelectedItem in the treeview to a property in the viewModel. Then you could also bind this property to a contentPresenter or any other form you want to represent it in. Ensure it has INotify working on it. So when you change the SelectedItem both the ViewModel and the representation (if you wan't one) in the view should be updated.
  • Bob Horn
    Bob Horn about 12 years
    But the whole problem in the first place is that the SelectedItem on the treeview is read only and can't be used in XAML. No?
  • Ingó Vals
    Ingó Vals about 12 years
    If it's read only it would mean you can't set it from the ViewModel or elsewhere except from a user selecting it in the GUI. You could still bind to it in a one way bind and show it in another control or do something with it in the ViewModel. I might be misunderstanding you. What are you trying to accomplish?
  • Bob Horn
    Bob Horn about 12 years
    I don't want to set it in the view model. I simply want the view model to know what the selected item is.
  • Ingó Vals
    Ingó Vals about 12 years
    Then I'm pretty sure you can just bind a property in the ViewModel of the proper type to the SelectedItem attribute in TreeView. You might have to set the mode to OneWay or OneWayToSource (can't remember which) but not sure.
  • Pentarex
    Pentarex almost 8 years
    Thank you for the solution :)
  • Shimmy Weitzhandler
    Shimmy Weitzhandler over 6 years
    Can I have the TreeView change a property in the ViewModel upon selection of an item?