views:

3069

answers:

3

I have a TreeView which uses a HierarchicalDataTemplate to bind its data.

It looks like this:

<TreeView x:Name="mainTreeList" ItemsSource="{Binding MyCollection}>
  <TreeView.Resources>
    <HierarchicalDataTemplate 
     DataType="{x:Type local:MyTreeViewItemViewModel}" 
     ItemsSource="{Binding Children}">
      <!-- code code code -->
    </HierarchicalDataTemplate>
  </TreeView.Resources>
</TreeView>

Now, from the code-behind of say the main window, I want to get the current selected TreeViewItem. However, if I use:

this.mainTreeList.SelectedItem;

The selectedItem is of type MyTreeViewItemViewModel. But I want to get the 'parent' or 'bound' TreeViewItem. I do not pass that to my TreeViewItemModel object (wouldn't even know how).

How can I do this?

+6  A: 

From Bea Stollnitz's blog entry about this, try

TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition));
Cameron MacFarland
Good enough for me, thanks. (it's a bit different though, CurrentItem returns an object and ContainerFromIndex takes an integer, so I had to use CurrentIndex or something, but oh well)
Razzie
Ah, I just copied-n-pasted from Bea's blog and then changed a few things. I didn't notice that error :) Still, I'll update my answer.
Cameron MacFarland
A: 

Do you need the TreeViewItem because you're going to modify what is being displayed? If that is the case, I'd recommend using a Style to change how the item is being displayed instead of using code-behind instead of directly modifying the TreeViewItem. It should hopefully be cleaner.

viggity
+2  A: 
TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition));

DOES NOT WORK (for me) as mainTreeList.Items.CurrentPosition in a treeview using a HierarchicalDataTemplate will always be -1.

NEITHER DOES below as as mainTreeList.Items.CurrentPosition in a treeview using a HierarchicalDataTemplate will always be null.

TreeViewItem item = (TreeViewItem)mainTreeList
    .ItemContainerGenerator
    .ContainerFromItem(mainTreeList.Items.CurrentItem);

INSTEAD I had to set a the last selected TreeViewItem in the routed TreeViewItem.Selected event which bubbles up to the tree view (the TreeViewItem's themselves do not exist at design time as we are using a HierarchicalDataTemplate).

The event can be captured in XAML as so:

<TreeView TreeViewItem.Selected="TreeViewItemSelected" .../> 

Then the last TreeViewItem selected can be set in the event as so:

    private void TreeViewItemSelected(object sender, RoutedEventArgs e)
    {
        TreeViewItem tvi = e.OriginalSource as TreeViewItem;

        // set the last tree view item selected variable which may be used elsewhere as there is no other way I have found to obtain the TreeViewItem container (may be null)
        this.lastSelectedTreeViewItem = tvi;

        ...
     }
Mrk Mnl
The only way for the CurrentItem to equal null (or CurrentIndex equaling -1) is if there are no items in the tree. Make sure there are items before trying to get the items container.
Cameron MacFarland
The CurrentItem is not the same as the SelectedItem. The ContainerFromItem returns null if it cannot find the container, and null can be cast to a TreeViewItem just fine without needing to use as cast. Did you even run the code?
Cameron MacFarland
The problem I think is you are using mainTreeList.Items which will only work for items in the first level of the treeview - each tree view node (TreeViewItem) has its own Items collection - unlike Bea's example which you quote which is using a ListBox and only has one level of items. It follows that you need to obtain reference currently selected TreeViewItem for which the only way I found to do so when using a HierarchicalDataTemplate is capturing the TreeViewItem.Selected event as in my answer.
Mrk Mnl
The reason CurrentItem returns null is only once a TreeViewItem is expanded are the next level of nodes instantiated. Admittedly this is not clear from the MSDN documentation.
Mrk Mnl