Медленное дерево в C # - PullRequest
       44

Медленное дерево в C #

9 голосов
/ 23 сентября 2008

У меня есть устаревшее приложение, написанное на C #, которое отображает очень сложное древовидное представление с 10-20 тысячами элементов.

В прошлом я сталкивался с подобной проблемой (но в C ++), которую я решил с помощью возможности OWNERDATA, предоставляемой Win32 API.

Есть ли подобный механизм в C #?

РЕДАКТИРОВАТЬ: план состоит в том, чтобы оптимизировать время создания, а также время просмотра. Метод, доступный через Win32 API, превосходен в обоих этих случаях, поскольку он сводит время инициализации к нулю, а количество запросов на элементы ограничено только теми, которые видны одновременно. Джошл: На самом деле мы делаем именно то, что вы предлагаете, но нам все еще нужно больше эффективности.

Ответы [ 6 ]

20 голосов
/ 23 сентября 2008

Одним из способов повышения производительности является загрузка TreeNodes, когда пользователь расширяет древовидную структуру. Обычно пользователю не требуется, чтобы на его экране одновременно открывалось 20 000 узлов. Загружайте только тот уровень, который должен видеть пользователь, вместе с любой дочерней информацией, которая вам необходима для правильного отображения разрешений для пользователя (разверните значок, если дети существуют, счетчики, значки и т. Д.). Когда пользователь расширяет узлы, вовремя загружайте дочерние элементы.

Полезный совет от Кейта: с древовидной формой TreeView у вас должен быть хотя бы один дочерний узел, иначе он не будет отображать расширение [+], но затем вы обрабатываете событие TreeNodeExpanded для удаления этого фиктивного узла и заполнения дочерних узлов.

11 голосов
/ 23 сентября 2008

В нашем главном приложении WinForm у нас загружено дерево всего за один снимок:

  • BeginUpdate ()
  • Загрузка 20 000 узлов
  • EndUpdate ()

и пока что производительность хорошая. На самом деле это один из немногих компонентов, которые мы не заменяем сторонними.

Производительность TreeView, по моему опыту, снижается при загрузке узлов (за один раз или по требованию) без вызова Begin / EndUpdate (), особенно если ваши узлы сортируются, но если вы вызываете Begin / EndUpdate () правильно, у вас не должно быть проблем с производительностью, связанных с самим компонентом.

7 голосов
/ 23 сентября 2008

ПРИМЕЧАНИЕ. Этот ответ недействителен из-за того, что спрашивающий сказал, что он уже делает подобные вещи, но я решил опубликовать его для дальнейшего использования другими пользователями, которые ищут по этой теме

Когда я делал подобные вещи в прошлом, я склонялся к наивному ленивому стилю загрузки.

  • Используйте свойство TreeNode.Tag для хранения ссылки, которую можно использовать для поиска детей
  • Используйте событие TreeView.BeforeExpand для заполнения дочерних узлов
  • При необходимости используйте событие TreeView.AfterCollapse для их удаления.
  • Чтобы отобразить поля [+] / [-], лучший способ, который я нашел, - создать одноэлементную пустышку TreeNode, которая добавляется в качестве дочерней для всех незаселенных узлов и вы проверяете ее существование до заполнения BeforeExpand.
7 голосов
/ 23 сентября 2008

Я не верю, что .NET TreeView поддерживает то, что вы хотите, хотя этот тип модели поддерживается DataGridView .NET (см. Свойство DataGridView VirtualMode ). TreeView позволит вам нарисовать ваши собственные узлы, но не позволит вам заполнить их из какого-то виртуального магазина.

Если возможно, вы можете рассмотреть возможность использования DataGridView для вашего приложения. В противном случае управление узлами вручную (как упоминалось выше в joshl) может сработать, если вы сможете обойти некоторые проблемы с обновлением экрана должным образом при расширении узлов. Помимо этого, вы можете обратиться к сторонним поставщикам, таким как этот (Divelements SandGrid) , который может (с акцентом на мощь) поддерживать желаемый режим работы.

ПРИМЕЧАНИЕ: SandGrid не поддерживается Divelements на конец июля 2013 года.

5 голосов
/ 23 сентября 2008

Существует один способ повысить производительность TreeView: создать все подузлы и соединить их вместе , а затем добавить узлы в TreeView. Если речь идет о графическом представлении.

TreeView tree = new TreeView();
TreeNode root = new TreeNode("Root");
PopulateRootNode(root); // Get all your data
tree.Nodes.Add(root);

В противном случае загружайте их узел за узлом, используя OnTreeNodeExpanded .

1 голос
/ 23 сентября 2008

Для больших данных в программировании Windows C #, будь то в WPF или WinForms, я традиционно добавляю узлы динамически. Я загружаю начальный корень дерева + детей + внуков глубоко. Когда какой-либо узел раскрывается, я загружаю узлы дерева, которые будут представлять внуков расширяющегося узла, если таковые имеются.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...