0

I am using HierarchicalDataTemplate to build my TreeView dynamicaly and don't know how to get the header of the selected item from treeview.

I tried to get it by the TreeViewItem.Selected event.

    private void TreeViewItem_OnItemSelected(object sender, RoutedEventArgs e)
    {
        TreeViewItem item = e.OriginalSource as TreeViewItem;
        string name = item.Header.ToString();
    }

but 'item.Header' is of type Node

this is my XAML-code:

<Window x:Class="MaschinenStoppScheduler.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:MyNamespace="clr-namespace:MaschinenStoppScheduler"
    Title="MaschinenStoppScheduler" Height="500" Width="900" Loaded="Window_Loaded_1">
<Window.DataContext>
    <MyNamespace:MainWindowVM />
</Window.DataContext>
<Grid>
    <TreeView x:Name="TreeViewGroups" TreeViewItem.Selected ="TreeViewItem_OnItemSelected"  
        ItemsSource="{Binding RootNodes}" HorizontalAlignment="Left" Margin="20,28,0,25" 
        VerticalAlignment="Stretch" Width="181" SelectedItemChanged="TreeViewGroups_SelectedItemChanged">
        <ItemsControl.ItemContainerStyle>
            <Style
            TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <HierarchicalDataTemplate DataType="{x:Type MyNamespace:Node}" ItemsSource="{Binding Children}">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>
        </ItemsControl.ItemTemplate>
    </TreeView>
</Grid>

Community
  • 1
  • 1
sanjar14
  • 47
  • 1
  • 10

1 Answers1

0

Yes, the selected item will be one of the items in RootNodes. Cast it to that type. Node, it seems to be. The header will be whatever property of that class you use for the header -- Name, it looks like.

private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    var treeView = sender as TreeView;

    var selectedNode = treeView.SelectedItem as Node;

    TreeViewItem tvi = treeView.ItemContainerGenerator.ContainerFromItem(treeView.SelectedItem) as TreeViewItem;
}

Node is the class contained in the collection you bound to ItemsSource on the TreeView. I've also included code demonstrating how to get the selected TreeViewItem.

  • Done: ((Node)item.Header).Name; – sanjar14 Sep 29 '16 at 21:49
  • Thank you! Another question: The SelectedItemChanged event returns for the SelectedItem null. Could please explain why – sanjar14 Sep 29 '16 at 21:53
  • private void TreeViewGroups_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) { TreeViewItem treeViewItem = TreeViewGroups.SelectedItem as TreeViewItem; } – sanjar14 Sep 29 '16 at 21:55
  • @sanjar14 do you mean when it changes to null? – 15ee8f99-57ff-4f92-890c-b56153 Sep 29 '16 at 23:19
  • in my example "treeViewItem" is always null. And my question is why? – sanjar14 Sep 30 '16 at 20:12
  • @sanjar14 `TreeViewGroups.SelectedItem` is not a `TreeViewItem`. It's a `Node`. It's one of the items from the collection you bound to `ItemsSource`. In WPF, you pretty much *never* touch `TreeViewItems`. You give the treeview instance of your class, and it gives you one back when the user selects it. This isn't winforms, things are very different. That's what I meant in my answer "the selected item will be one of the items in RootNodes. Cast it to that type. Node" – 15ee8f99-57ff-4f92-890c-b56153 Sep 30 '16 at 20:15
  • something like this? var treeViewItem = TreeViewGroups.SelectedItem as Node; If so how can i use treeViewItem.IsSelected = false or treeViewItem.Focus() in code behind? Sorry I'm a beginner – sanjar14 Sep 30 '16 at 20:35
  • @sanjar14 What is `sender`? Put a breakpoint in the event handler and hover your mouse over `sender`. See what type it is. – 15ee8f99-57ff-4f92-890c-b56153 Sep 30 '16 at 20:36
  • `SelectedItem` and `SelectedValue` of sender is of type Node – sanjar14 Sep 30 '16 at 20:41
  • `sender` is `System.Windows.Controls.TreeView` – sanjar14 Sep 30 '16 at 20:47
  • You can get the TreeViewItem from the SelectedItem value like so (not exactly obvious!): http://stackoverflow.com/a/5218687/424129 – 15ee8f99-57ff-4f92-890c-b56153 Sep 30 '16 at 21:01
  • It returns also null. The items of `ItemContainerGenerator`are of type Node – sanjar14 Sep 30 '16 at 21:17
  • @sanjar14 No, that's not true. Not unless you're passing it garbage. See update to answer. That's working code that I copied directly out of my test project in Visual Studio. – 15ee8f99-57ff-4f92-890c-b56153 Sep 30 '16 at 21:25
  • I just copied your code. It does not work. The problem must lie elsewhere. – sanjar14 Sep 30 '16 at 21:49
  • @sanjar14 Wait a minute, you're handling ItemSelected in your question. I did a handler for SelectedItemChanged. Different events. I goofed. Which did you use my handler for? – 15ee8f99-57ff-4f92-890c-b56153 Sep 30 '16 at 21:51
  • The problem with the handler `TreeViewItem.Selected` has indeed solved. I'm working now with the handler `SelectedItemChanged`. There I copied your code in it and set the value IsSelected of the current TreeViewItem to false. – sanjar14 Sep 30 '16 at 22:04
  • I'm using the same handler like you – sanjar14 Sep 30 '16 at 22:05
  • @sanjar14 So what didn't work, just deselecting? You're not going to be able to deselect in the selection changed event. What you could try doing is BeginInvoke with the idle state flag, so your code will happen after the event finishes -- I don't recall the details but here are lots of examples around here – 15ee8f99-57ff-4f92-890c-b56153 Sep 30 '16 at 22:32
  • @sanjar14 maybe not examples for TreeView selection in particular, more like changing a bound property back to its original value when a binding updates it. Same principle. – 15ee8f99-57ff-4f92-890c-b56153 Sep 30 '16 at 22:35
  • No it returns null by selecting. With `BeginInvoke` it does not work unfortunately. Can I send you my program and you looking at why it does not work? – sanjar14 Oct 01 '16 at 21:37
  • @sanjar14 1. Call `BeginInvoke(DispatcherPriority.ContextIdle, (Action)()=>{...})`. That way, the lambda is invoked *after* the SelectedItemChanged event is fully complete. 2. ALL code that you want to execute after the event handler MUST go in the lambda. ALL OF IT. You left the important part in the handler where you already know it won't work. 3. I think that sleazy file transfer site gave me a virus. Use DropBox instead, it's safe and it's free. 4. That's two answers for the price of one, you owe me another 15 pts ha ha. – 15ee8f99-57ff-4f92-890c-b56153 Oct 02 '16 at 12:41
  • I have followed the steps you have described, but "tvi" always has the value null. Set a breakpoint at the if statement in lambda expression and you will see it. Here my programm again. https://www.dropbox.com/s/ar1pqoglsxm8wjc/WpfTest.zip?dl=0 – sanjar14 Oct 07 '16 at 07:32
  • @sanjar14 See [this answer](http://stackoverflow.com/a/6713032/424129): It's ugly. However, I'm even uglier, so I wrote a nice little generic recursive extension method. Since the question has been asked before, and all the answers are either "good luck writing your own" or else truly horrible code, why don't you ask that as a separate question, and I'll answer it with my recursive thing. – 15ee8f99-57ff-4f92-890c-b56153 Oct 07 '16 at 14:14