WPF ListBox - получение UIElement вместо SelectedItem

Я создал ListBox с DataTemplate как Itemtemplate. Однако есть ли простой способ получить доступ к сгенерированному UIElement вместо SelectedItem в codebehind?

Когда я получаю доступ к SelectedItem, я просто получаю выбранный объект из своего ItemsSource коллекция. Есть ли способ доступа к UIElement (т.е. элемент, сгенерированный из DataTemplate вместе со связанным объектом)?

Ответ 1

Вы ищете свойство ItemContainerGenerator. Каждый ItemsSource имеет экземпляр ItemContainerGenerator. Этот класс имеет следующий метод, который может вас заинтересовать: ContainerFromItem (экземпляр объекта).

Когда у вас есть дескриптор ListBoxItem, вы можете перейти к просмотру логического и визуального дерева. Проверьте помощник по логическому дереву и помощник по визуальному дереву.

Как сказал Энди в комментариях, тот факт, что элемент существует в вашей коллекции, не означает, что для него создан контейнер. Любой вид сценария виртуализации панели поднимет эту проблему; Элементы UIE будут повторно использоваться в различных элементах. Будьте осторожны с этим.

Ответ 2

siz, Энди и Бодейкер абсолютно правы.

Вот как я смог получить текстовое поле выбранного элемента списка с помощью его дескриптора.

var container = listboxSaveList.ItemContainerGenerator.ContainerFromItem(listboxSaveList.SelectedItem) as FrameworkElement;
if (container != null)
{
    ContentPresenter queueListBoxItemCP = VisualTreeWalker.FindVisualChild<ContentPresenter>(container);
    if (queueListBoxItemCP == null)
        return;

    DataTemplate dataTemplate = queueListBoxItemCP.ContentTemplate;

    TextBox tbxTitle = (TextBox)dataTemplate.FindName("tbxTitle", queueListBoxItemCP);
    tbxTitle.Focus();
}

(Примечание: здесь VisualTreeWalker является моей собственной оболочкой над VisualTreeHelper с различными полезными функциями)