2008-09-23 4 views
8

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

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

Есть ли аналогичный механизм в C#?

EDIT: Планируется оптимизировать время создания, а также время просмотра. Метод, доступный через API Win32, превосходен в обоих случаях, поскольку он уменьшает время инициализации до нуля, а количество запросов для элементов ограничено только теми, которые видны в любой момент времени. Joshl: Мы на самом деле делаем именно то, что вы предлагаете, но нам все еще нужна более эффективная работа.

ответ

6

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

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

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

19

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

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

+1

Задержка загрузки ... Я считаю, что это называется. Хороший ответ. – Gishu 2008-09-23 14:23:36

+0

Этот ответ, очевидно, хорош, так как это уже было что-то, что было реализовано на моей стороне. – 2008-09-23 14:27:53

4

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

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

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

7

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

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

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

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

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

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

8

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

  • BeginUpdate()
  • нагрузки 20.000 узлов
  • EndUpdate()

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

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

Смежные вопросы