Обработано TreeView.SelectedItemChanged событие все еще пузыри - PullRequest
6 голосов
/ 25 мая 2011

У меня есть TreeView, привязанный к иерархии, состоящей из нескольких разных классов через HierarchicalDataTemplate s.Когда элемент в дереве выбран, событие SelectedItemChanged, конечно, радостно всплывает вверх через родительские элементы, как и должно быть.То, что он должен не делать, но продолжает делать, радостно продолжает пузыриться после того, как я установил e.Handled в true.

Событие все равно будет срабатывать для родительского элемента, иRoutedPropertyChangedEventArgs будет выглядеть точно так же, как был выбран родительский элемент;даже свойство OriginalSource будет указывать на родительский элемент, а не тот, который был первоначально выбран.e.Handled конечно будет false.

Почти тот же вопрос был задан здесь , но я не использую EventAggregator или CAL, и найденный обходной путь здесь мало помогает, потому чтоЯ не специально после события мыши.

Есть ли способ точно получить элемент, который был фактически выбран или принудительно остановить кипящее безумие (не прибегая к очень насильственному и неэтичному взлому с использованием глобальных переменных, которые яможет придумать)?

Спасибо за любые идеи.

Ответы [ 2 ]

2 голосов
/ 25 мая 2011

Прочитав ответ Рика, я поговорил с коллегой, у которого, как оказалось, раньше была такая же проблема.Я пробовал разные вещи в своем приложении (обнаружение: событие TreeViewItem.Selected ведет себя точно так же неправильно) и в тестовом проекте и обнаружил, что в тестовом приложении события запускались именно так, как и следовало ожидать.Таким образом, должно было быть значительное различие в окружении (классы XAML и ViewModel были почти идентичны), которое привело к этой разнице в поведении - и виновник выглядит как COM, точно размещая элементы управления WPF в приложении COM.

Приложение моего коллеги - это расширение Word, использующее VSTO, в то время как мое - VSPackage для Visual Studio 2010 - и Word, и VS2010 по-прежнему по большей части являются нативным кодом.Мое тестовое приложение, с другой стороны, конечно, небольшой проект WPF.Я добавил форму WinForms с ElementHost, которая, в свою очередь, размещала UserControl с TreeView, но она все еще работала как надо, поэтому мне действительно кажется, что хост-приложение COM каким-то образом вмешивается в события, возникающие вTreeView и TreeViewItems.

К счастью, мой коллега нашел / нашел решение, которое покажет - после того, как вы закончите с фактической реакцией на событие, в конце метода обработчика события, сноваустановите TreeViewItem как выбранный и сфокусируйте его:

item.Focus();
item.IsSelected = true;

Мы не понимаем, почему, но это остановит ошибочный повторный выбор элементов (это, очевидно, не является пузырьковым событием в смысле WPF).

Еще раз спасибо Рику за то, что он поддержал раздвоение событий TreeView и TreeViewItem.

2 голосов
/ 25 мая 2011

Ваш вопрос озадачивает меня, потому что событие SelectedItemChanged является событием TreeView, а не TreeViewItem. «Эй, чувак, мое мероприятие не было близко к вашему мероприятию!»

Когда выбранный элемент изменяется, TreeView вызывает событие SelectedItemChanged для самого , TreeView и , если не обработано , оно начинает пузыриться к корневому элементу страницы.

Написание небольшой тестовой программы помогает, когда вам нужны доказательства.

Вот небольшой TreeView, содержащийся в Grid:

<Grid TreeView.SelectedItemChanged="Grid_SelectedItemChanged">
    <TreeView SelectedItemChanged="TreeView_SelectedItemChanged">
        <TreeViewItem TreeView.SelectedItemChanged="TreeViewItem_SelectedItemChanged" Header="Item1">
            <TreeViewItem TreeView.SelectedItemChanged="TreeViewItem_SelectedItemChanged" Header="Item2">
                <TreeViewItem TreeView.SelectedItemChanged="TreeViewItem_SelectedItemChanged" Header="Item3"/>
            </TreeViewItem>
        </TreeViewItem>
    </TreeView>
</Grid>

и вот код для теста:

private void Grid_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    SelectedItemChanged(sender, e, "Grid");
}

private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    SelectedItemChanged(sender, e, "TreeView");
    e.Handled = true;
}

private void TreeViewItem_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    SelectedItemChanged(sender, e, "TreeViewItem");
}

private void SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e, string handler)
{
    Debug.WriteLine("");
    Debug.WriteLine(string.Format("SelectedItemChanged: handler = {0}", handler));
    Debug.WriteLine(string.Format("e.NewValue.Header = {0}", (e.NewValue as TreeViewItem).Header));
    Debug.WriteLine(string.Format("sender = {0}", sender));
    Debug.WriteLine(string.Format("e.Source = {0}", e.Source));
    Debug.WriteLine(string.Format("e.OriginalSource = {0}", e.OriginalSource));
}

и запуск его и нажатие на первый элемент приводит к выводу отладки:

SelectedItemChanged: handler = TreeView
e.NewValue.Header = Item1
sender = System.Windows.Controls.TreeView Items.Count:1
e.Source = System.Windows.Controls.TreeView Items.Count:1
e.OriginalSource = System.Windows.Controls.TreeView Items.Count:1

, который показывает, что событие вызывается на самом TreeView, а установка e.Handled на true предотвращает получение события Grid. Прокомментируйте эту строку и она всплывет до Grid.

Но ни в коем случае TreeViewItem никогда не вызывал обработчик SelectedItemChanged.

Попробуйте использовать небольшие тестовые программы, когда все идет не так, как вы думаете. Гораздо проще проводить эксперименты и разобраться в сути проблемы!

...