Получить TreeViewItem для логического элемента TreeView

Мое представление дерева выглядит так

<TreeView x:Name="ArticlesTreeView" Grid.Column="0" AllowDrop="True">
            <TreeView.Resources>
                <HierarchicalDataTemplate   DataType="{x:Type structure:NewsPaperDocument}" ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}" Tag="{Binding Object}" FontWeight="Bold" />
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type structure:NewsPaperPage}" ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}" Tag="{Binding Object}" Foreground="#00a300" />
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type structure:NewsPaperTitle}" ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}" Tag="{Binding Object}" Foreground="#da532c" />
                </HierarchicalDataTemplate>
                <DataTemplate DataType="{x:Type structure:NewsPaperBlock}">
                    <TextBlock Text="{Binding Name}" Tag="{Binding Object}" Foreground="#2b5797" />
                </DataTemplate>
            </TreeView.Resources>
        </TreeView>

В ArticlesTreeView.SelectedItem хранится экземпляр классов NewsPaperDocument, NewsPaperPage, etc. Как я могу связать TreeViewItem с SelectedItem? Я пытаюсь использовать VisualTreeHelper.GetParent(elem);, но SelectedItem не имеет типа DependencyObject

UPD1 Добавьте простой образец, демонстрирующий проблему. item в ArticlesTreeView_SelectedItemChanged всегда null

XAML

<Window x:Class="TestTree.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:testTree="clr-namespace:TestTree"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <TreeView x:Name="ArticlesTreeView" Grid.Column="0" AllowDrop="True" SelectedItemChanged="ArticlesTreeView_SelectedItemChanged">
        <TreeView.Resources>
            <HierarchicalDataTemplate   DataType="{x:Type testTree:A}" ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}" FontWeight="Bold" />
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type testTree:B}" ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}" Foreground="#00a300" />
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type testTree:C}">
                <TextBlock Text="{Binding Name}" Foreground="#2b5797" />
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>
</Grid>

CS

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace TestTree
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var a = new A
            {
                Name = "a",
                Children = new List<B>
                {
                    new B
                    {
                        Name = "b1",
                        Children = new List<C>
                        {
                            new C{Name = "c1"},
                            new C{Name = "c2"},
                            new C{Name = "c3"}
                        },
                    },
                    new B
                    {
                        Name = "b2",
                        Children = new List<C>
                        {
                            new C{Name = "c1"},
                            new C{Name = "c2"},
                            new C{Name = "c3"}
                        },
                    },
                    new B
                    {
                        Name = "b3",
                        Children = new List<C>
                        {
                            new C{Name = "c1"},
                            new C{Name = "c2"},
                            new C{Name = "c3"}
                        },
                    }
                }
            };
            ArticlesTreeView.ItemsSource = new List<A> { a };
        }

        private void ArticlesTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            ItemContainerGenerator gen = ArticlesTreeView.ItemContainerGenerator;
            var item = gen.ContainerFromItem(ArticlesTreeView.SelectedItem);
        }
    }

    internal class A
    {
        public string Name { set; get; }

        public List<B> Children { set; get; }
    }

    internal class B
    {
        public string Name { set; get; }

        public List<C> Children { set; get; }
    }

    internal class C
    {
        public string Name { set; get; }
    }
}

person beta-tank    schedule 21.07.2014    source источник
comment
ArticlesTreeView.SelectedItem это TreeViewItem. Ваша проблема заключается в получении TreeView? я не уверен, что понимаю вашу проблему   -  person Yuval Itzchakov    schedule 21.07.2014
comment
@YuvalItzchakov Если вы создаете свое дерево, вручную добавляя TreeViewItem к дереву, это правильно. Но я использую HierarchicalDataTemplate, и мое дерево создается автоматически из коллекции. Тип SelectedItem и SelectedValue равен NewsPaperBlock или т. д.   -  person beta-tank    schedule 21.07.2014


Ответы (1)


если я вас правильно понял, вы хотите получить TreeViewItem из SelectedItem

так что вы можете использовать ItemContainerGenerator

        ItemContainerGenerator gen = ArticlesTreeView.ItemContainerGenerator;
        TreeViewItem item = gen.ContainerFromItem(ArticlesTreeView.SelectedItem) as TreeViewItem;

Получить TreeViewItem из вложенных элементов

по той причине, что каждый TreeViewItem имеет свой собственный ItemContainerGenerator, поэтому, чтобы найти контейнер из вложенных элементов, нам нужно рекурсивно выполнить глубину дерева

    private void ArticlesTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        var item = ContainerFromItem(ArticlesTreeView.ItemContainerGenerator, ArticlesTreeView.SelectedItem);
    }

    private static TreeViewItem ContainerFromItem(ItemContainerGenerator containerGenerator, object item)
    {
        TreeViewItem container = (TreeViewItem)containerGenerator.ContainerFromItem(item);
        if (container != null)
            return container;

        foreach (object childItem in containerGenerator.Items)
        {
            TreeViewItem parent = containerGenerator.ContainerFromItem(childItem) as TreeViewItem;
            if (parent == null)
                continue;

            container = parent.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (container != null)
                return container;

            container = ContainerFromItem(parent.ItemContainerGenerator, item);
            if (container != null)
                return container;
        }
        return null;
    }
person pushpraj    schedule 21.07.2014
comment
Я пытаюсь, но gen.ContainerFromItem(ArticlesTreeView.SelectedItem) возвращает null, когда ArticlesTreeView.SelectedItem не null - person beta-tank; 21.07.2014
comment
это может произойти из-за виртуализации. Важным моментом здесь является то, что TreeViewItem или Container могут быть получены только тогда, когда они сгенерированы, поэтому элемент должен быть загружен и/или в представлении, если это не так, вы можете прокрутить элемент до извлечения контейнера. просто убедитесь, что вы извлекаете контейнер (TreeViewItem), когда вы его видите, иначе есть вероятность, что контейнер еще не создан или был переработан в какой-то другой элемент. - person pushpraj; 21.07.2014
comment
в Snoop все TreeViewItems созданные и выбранные элементы видны в моем представлении - person beta-tank; 21.07.2014
comment
Вы можете опубликовать рабочий образец вашего кода, который может воспроизвести проблему? посмотрим, как мы можем исправить это для вашего случая. - person pushpraj; 21.07.2014
comment
добавить образец в первое сообщение - person beta-tank; 21.07.2014
comment
обновленный ответ также для получения из вложенного элемента, предыдущий подход предполагал прямые дочерние элементы дерева - person pushpraj; 21.07.2014