СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

| сохранено

H TreeView + WPF — мы так привыкли к халяве WinForms… в черновиках

Доброго времени суток! Написать эту статью решил после очень пристрастного знакомства с особенностями работы WPF-контрола TreeView, особенно после очень хорошего опыта использования его младшего собрата из WinForms.

Я конечно не истина в последней инстанции, но, когда что-то не работает — ооооочень сильно бесит, когда такое же работает на другой технологии на раз. Более того — для своей работы требует очень безграничного внимания чтобы заставить это работать по-человечески. А документация не просто хромает на обе ноги — она просто переломана даже на руки по самую шею, поэтому она по гуглю и яндексу ползет передвигаясь переломанными челюстями из тех обрывков опыта, что поимели (или их уже опыт поимел) участвующих.

Передо мной стояло две основные задачи к TreeView:

1) Отобразить выбор элемента дерева
2) Позиционировать визуально на выбранный узел окно дерева, если элемент был вне зоны видимости

Как решалось:

1) Проблема выбора элемента

Те, кто работал с WinForms, привыкли, что выбор элемента — это просто приравнивание его к селекту. А тут — эээээ… только для чтения???? Да вы издеваетесь???? Ага, ООП — всегда издевается…

Просто, если быть объектом чего-то в пространстве, то нет наивысшей степени свободы от всего, нежели все собственное!

Теперь, чтобы выбор пал на элемент дерева — НАДО НЕ ДЕРЕВУ СКАЗАТЬ, что выбрать, а ЭЛЕМЕНТУ ДЕРЕВА поставить свойство IsSelected=true; То есть — берете TreeViewItem и ему даете флаг видимости. Выполнили. В WPF не дерево решает что выбрать, а компонет сам решает быть ли ему выбранным.

2) Тут вообще весело — в интернете нет ни единой внятной строки как это сделать. Помогли только знания английского и воображение. Причем воображение — сильнее всего! Почему? Да потому, если хочешь видимость узла дерева — так назначай этому узлу видимость. Я аж… ел от такого назначения очевидности. А Капитан-очевидность до сих пор нервно пьет сок в углу комнаты, глядя на эти маневры.

В общем — если надо видеть что-то в это гребаном компоненте, то надо использовать метод .BringIntoView(); Только тогда тот «контент-вьювер», сообразит, что вам надо показать так как вы этого хотели.

И еще один неприятный момент: выделить и показать — пол-дела! надо еще и отобразить! Даааааа, чтобы элемент позиционировать в окне контрола — надо его еще и развернуть по дереву! :) А вы думали! Извращения — это наше все!!! Теперь чтобы выделенный по IsSelected и развернутый по IsExpanded был видим — надо развернуть всю подноготную компонета по пути этого самого дерева. Я для себя делаю это вызовом следующего метода:

        private void ExpandGroups(TreeViewItem tvi)
        {
            if (tvi.Parent!=null)
            {
                if (tvi.Parent.GetType() == typeof(TreeViewItem))
                {
                    ((TreeViewItem)tvi.Parent).IsExpanded = true;
                    this.ExpandGroups((TreeViewItem)tvi.Parent);
                }
            }
        }

Он разворачивает то, что нужно, до того куда нужно… универсально.

комментарии (6)

+4
kahi4 ,  
Теперь, чтобы выбор пал на элемент дерева — НАДО НЕ ДЕРЕВУ СКАЗАТЬ, что выбрать, а ЭЛЕМЕНТУ ДЕРЕВА поставить свойство IsSelected=true;

Это достаточно типичное поведение для MVVM, особенно различных реализаций патерна observable и звучит примерно так "подписывайтесь на изменения как можно ближе к его непосредственному использованию". Иными словами, это позволяет WPF-у перерисовывать только изменившиеся части, а не все дерево.


Тут вообще весело — в интернете нет ни единой внятной строки как это сделать. Помогли только знания английского и воображение.

Как-то раз SELinux резал права на чтение файла tmux-у. Вот где понадобилось умение гуглить, знание английского и невероятное умение. Тут же, при всем уважении, больше похоже на невнимательный просмотр MDSN (шутка, что "если на MDSN нет решения, то вы что-то делаете не так" родилась не на пустом месте).

+1
kekekeks ,  
И еще один неприятный момент: выделить и показать — пол-дела! надо еще и отобразить! Даааааа, чтобы элемент позиционировать в окне контрола — надо его еще и развернуть по дереву

Вы же в курсе, что тривью работает в режиме виртуализации и не создаёт элементы управления для скрытых веток? Это позволяет в него запихнуть несколько миллионов элементов и всё это счастье не будет тормозить и кушать гигабайты памяти. Это одна из причин, по которой тривью не делает никаких предположений о структуре вашего дерева и отдаёт манипуляции с ним на откуп разработчику.

0
+1 –1
Error1024 ,  
Было бы круто, если бы при этом WPF тормозило меньше чем «неоптимальный» WinForms.
+1
Einherjar ,  
Наличие или отсутствие тормозов зависит только от степени рукопопия разработчика. Но на реально сложных интерфейсах на винформс слишком много костылей приходится добавлять.
+1
+2 –1
Nexelen ,  
Это по вашему статья?
+1
wlbm_onizuka ,  
Было бы странно, если бы столь идеологически разные технологии реализовывали одни и те же сценарии похожим образом.
WinForms предлагает привычный императивный стиль, где мы указываем компонентам что им делать.
Про WPF лучше сначала книги почитать чтобы понять идеологию.
RTFM и нет проблем!