3

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"); }
}  
GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Joseph jun. Melettukunnel
  • 6,267
  • 20
  • 69
  • 90

4 Answers4

6

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.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Ingó Vals
  • 4,788
  • 14
  • 65
  • 113
  • 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? – Bob Horn Feb 04 '12 at 04:05
  • 1
    @ 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. – Ingó Vals Feb 08 '12 at 14:12
  • 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? – Bob Horn Feb 08 '12 at 16:50
  • 1
    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? – Ingó Vals Feb 08 '12 at 17:16
  • I don't want to set it in the view model. I simply want the view model to know what the selected item is. – Bob Horn Feb 08 '12 at 17:33
  • 1
    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. – Ingó Vals Feb 09 '12 at 09:10
  • Can I have the `TreeView` change a property in the ViewModel upon selection of an item? – Shimmy Weitzhandler Nov 21 '17 at 21:24
5

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
        }
Diego Torres
  • 1,213
  • 12
  • 5
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.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
mwck46
  • 148
  • 9
2

Maybe I've misunderstood your question but,

treeView1.SelectedItem

Should work.

Charlie
  • 15,069
  • 3
  • 64
  • 70