Get SelectedItem from TreeView?
Asked Answered
D

4

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"); }
}  
Darcie answered 6/8, 2009 at 11:28 Comment(1)
What are you trying to do? Why doesn't TreeView.SelectedItem not work for you?Onitaonlooker
R
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.

Rapper answered 5/7, 2010 at 14:33 Comment(7)
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?Troup
@ 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.Chanty
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?Troup
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?Chanty
I don't want to set it in the view model. I simply want the view model to know what the selected item is.Troup
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.Chanty
Can I have the TreeView change a property in the ViewModel upon selection of an item?Sundowner
R
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
        }
Raillery answered 29/9, 2015 at 13:23 Comment(1)
Thank you for the solution :)Genuflect
S
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.

Stunning answered 1/11, 2019 at 10:9 Comment(0)
M
2

Maybe I've misunderstood your question but,

treeView1.SelectedItem

Should work.

Mercury answered 6/8, 2009 at 15:46 Comment(1)
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)Darcie

© 2022 - 2024 — McMap. All rights reserved.