2008-09-23 23 views
8

Tengo una aplicación heredada que está escrita en C# y muestra una vista de árbol muy compleja con 10 a 20 mil elementos.Vista de árbol lenta en C#

En el pasado me encontré con un problema similar (pero en C++) que resolví con la capacidad OWNERDATA ofrecida por la API de Win32.

¿Hay un mecanismo similar en C#?

EDITAR: El plan es optimizar el tiempo de creación así como el tiempo de exploración. El método disponible a través de la API Win32 es excelente en ambos casos, ya que reduce el tiempo de inicialización a nada y el número de solicitudes de elementos se limita a solo las visibles en cualquier momento. Joshl: En realidad estamos haciendo exactamente lo que sugiere, pero aún necesitamos más eficiencia.

Respuesta

6

No creo que .NET TreeView sea compatible con lo que desee, aunque este tipo de modelo es compatible con DataGridView de .NET (consulte la propiedad VirtualMode de DataGridView). TreeView te permitirá dibujar tus propios nodos pero no te permitirá poblarlos desde alguna tienda virtual.

Si es posible, es posible que desee considerar el uso de un DataGridView para su aplicación. De lo contrario, administrar los nodos manualmente (como las menciones de joshl anteriores) podría funcionar si puede solucionar algunos problemas al actualizar la pantalla correctamente cuando se expanden los nodos. Fuera de eso, es posible que desee consultar algunos de los proveedores de terceros, como this one (Divelements SandGrid), que podrían (con énfasis en podría) apoyar el modo de operación deseado.

NOTA: El SandGrid no es compatible con Divelements a partir de finales de julio de 2013.

+1

El modo virtual de DataGridView parece ajustarse perfectamente a la factura. Muchas gracias por la respuesta rápida. –

19

Una técnica para mejorar el rendimiento es cargar TreeNodes a medida que el usuario expande la vista de árbol. Normalmente, un usuario no requerirá que 20,000 nodos se abran en su pantalla a la vez. Cargue únicamente el nivel que el usuario necesita ver, junto con la información necesaria para que el niño muestre las posibilidades al usuario (expanda el ícono si existen, cuenta, iconos, etc.). A medida que el usuario expande los nodos, cargue los niños justo a tiempo.

Consejo útil de Keith: con los winforms TreeView necesita tener al menos un nodo hijo o no mostrará la expansión [+], pero luego maneja el evento TreeNodeExpanded para eliminar ese nodo ficticio y poblar los hijos .

+1

Delay loading ... Creo que esto se llama. Buena respuesta. – Gishu

+0

Esta respuesta obviamente es buena y ya fue algo que se implementó de mi lado. –

+0

Con los winforms TreeView necesita tener al menos un nodo secundario o no mostrará la expansión [+], pero luego maneja el evento TreeNodeExpanded para eliminar ese nodo ficticio y poblar los elementos secundarios. – Keith

4

Hay una manera de hacer que el TreeView un desempeño mucho mejor y que es la creación de todos los sub-nodos y engancharlos juntos y luego agregue los nodos a TreeView. Si es el rendimiento gráfico del que estamos hablando.

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

De lo contrario, cargarlos nodo por nodo utilizando OnTreeNodeExpanded.

7

NOTA: Esta respuesta es invalidada por una edición por el interrogador diciendo que ya lo hace este tipo de cosas, pero decidió todavía publicar para futuras consultas por otros que buscan en este tema

cuando estoy he hecho cosas similares en el pasado, he tendido a optar por el estilo ingenuo de carga lenta.

  • TreeNode.Tag utilizar la propiedad para almacenar una referencia que se puede utilizar para buscar a los niños-
  • utilizar el evento TreeView.BeforeExpand para rellenar los nodos secundarios
  • utilizar Opcionalmente caso TreeView.AfterCollapse para eliminarlos.
  • Para que aparezcan los recuadros [+]/[-], la mejor forma que he encontrado es crear un comodín singleton TreeNode que se agrega como un niño a todos los Nodos despoblados, y verifica su existencia antes de poblar con BeforeExpand.
1

Para datos grandes en la programación de Windows C#, ya sea en WPF o WinForms, tradicionalmente he agregado nodos dinámicamente. Cardo la raíz del árbol inicial + hijos + nietos en profundidad. Cuando se expande cualquier nodo, cargo los nodos de árbol que representarían a los nietos del nodo en expansión, si hay alguno.

Este patrón también funciona bien con la recuperación de datos. Si realmente está cargando datos de una fuente de miles o millones de registros, probablemente no quiera cargarlos por adelantado. Ningún usuario quiere esperar a que se cargue, y no hay razón para cargar datos que quizás nunca se visualicen.

Normalmente he cargado los datos del nodo nietos o bisnietos según sea necesario en un hilo de fondo, luego marcalizo esos datos al hilo de la interfaz de usuario y creo y agrego los nodos. Esto deja la IU receptiva. Puede decorar visualmente nodos de árbol para indicar que aún se están cargando para el caso en que un usuario se adelanta a su IO en el almacén de datos.

8

En nuestra aplicación principal WinForm, tenemos una vista de árbol cargado todo de una sola vez:

  • BeginUpdate()
  • carga 20.000 nodos
  • EndUpdate()

y hasta el momento el rendimiento sigue siendo bueno. En realidad, es uno de los pocos componentes que no reemplazamos con los de terceros.

El rendimiento de TreeView, según mi experiencia, se vuelve lento cuando carga nodos (de una sola vez o bajo demanda) sin llamar a Begin/EndUpdate(), especialmente si los nodos están ordenados, pero si llama a Begin/EndUpdate () correctamente, realmente no debería tener problemas de rendimiento relacionados con el componente en sí.