This article is currently in the process of being translated into Spanish (~99% done).
Lazy loading TreeView items
El proceso habitual cuando se utiliza TreeView es unirse a una colección de elementos o agregar manualmente cada nivel al mismo tiempo. Sin embargo, en algunas situaciones, puede ser deseable retrasar la carga de elementos secundarios de un nodo hasta que realmente se necesiten. Esto es especialmente útil si tienes un árbol muy profundo, con muchos niveles y nodos secundarios y un gran ejemplo de esto, es la estructura de carpetas de su computadora con Windows.
Cada unidad en su computadora con Windows tiene una gama de carpetas secundarias, y cada una de esas carpetas secundarias tiene carpetas secundarias debajo de ellas, etc. Mediante un bucle a través de cada unidad y cada unidad hila, las carpetas secundarias podrían consumir mucho tiempo y su TreeView pronto consistiría en muchos nodos, con un alto porcentaje de ellos que nunca se necesitan. Esta es la tarea perfecta para un TreeView cargado de forma diferida, donde las carpetas secundarias solo se cargan a pedido.
Para lograr esto, simplemente agregamos una carpeta ficticia a cada unidad o carpeta secundaria, y luego, cuando el usuario la expande, eliminamos la carpeta ficticia y la reemplazamos con los valores reales Así es como se ve nuestra aplicación cuando se inicia: en ese momento, solo hemos obtenido una lista de unidades disponibles en la computadora:
Ahora puede comenzar a expandir los nodos, y la aplicación cargará automáticamente las subcarpetas. Si una carpeta está vacía, se mostrará vacía una vez intenta expandirlo, como se puede ver en la siguiente captura de pantalla:
Entonces, ¿cómo se logra? Echemos un vistazo al código:
<Window x:Class="WpfTutorialSamples.TreeView_control.LazyLoadingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="LazyLoadingSample" Height="300" Width="300">
<Grid>
<TreeView Name="trvStructure" TreeViewItem.Expanded="TreeViewItem_Expanded" Margin="10" />
</Grid>
</Window>
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
namespace WpfTutorialSamples.TreeView_control
{
public partial class LazyLoadingSample : Window
{
public LazyLoadingSample()
{
InitializeComponent();
DriveInfo[] drives = DriveInfo.GetDrives();
foreach(DriveInfo driveInfo in drives)
trvStructure.Items.Add(CreateTreeItem(driveInfo));
}
public void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
{
TreeViewItem item = e.Source as TreeViewItem;
if((item.Items.Count == 1) && (item.Items[0] is string))
{
item.Items.Clear();
DirectoryInfo expandedDir = null;
if(item.Tag is DriveInfo)
expandedDir = (item.Tag as DriveInfo).RootDirectory;
if(item.Tag is DirectoryInfo)
expandedDir = (item.Tag as DirectoryInfo);
try
{
foreach(DirectoryInfo subDir in expandedDir.GetDirectories())
item.Items.Add(CreateTreeItem(subDir));
}
catch { }
}
}
private TreeViewItem CreateTreeItem(object o)
{
TreeViewItem item = new TreeViewItem();
item.Header = o.ToString();
item.Tag = o;
item.Items.Add("Loading...");
return item;
}
}
}
El XAML es muy simple y solo hay un detalle interesante: la forma en que nos suscribimos al evento expandido de TreeViewItem. Nótese que este es de hecho el TreeViewItem y no el TreeView en sí mismo, pero debido a que el evento brota, podemos capturarlo en un solo lugar para el TreeView completo, en lugar de tener que suscribirse a él para cada elemento que agreguemos al árbol. Este evento se llama cada vez que se expande un elemento, que necesitamos tener en cuenta para cargar sus artículos secundarios a pedido.
En Código subyacente , comenzamos agregando cada unidad que se encuentra en la computadora al control TreeView. Asignamos la instancia DriveInfo a la propiedad Tag, para que luego podamos recuperarla. Tenga en cuenta que usamos un método personalizado para crear el TreeViewItem, llamado CreateTreeItem () , ya que podemos usar exactamente el mismo método cuando queremos agregar dinámicamente una carpeta secundaria más adelante. Nótese como en este método cómo agregamos un elemento secundario a la colección Elementos, en forma de una cadena con el texto "Cargando ...".
El siguiente es el evento TreeViewItem_Expanded. Como ya se mencionó, este evento se genera cada vez que se expande un elemento TreeView, por lo que lo primero que hacemos es comprobar si este elemento ya se ha cargado, verificando si los elementos secundarios actualmente consisten en un solo elemento, que es una cadena; si es así, tenemos que encontrar el elemento secundario "Cargando ...", lo que significa que ahora deberíamos cargar el contenido real y reemplazar el elemento de marcador de posición con él.
Ahora usamos la propiedad Etiqueta de elementos para obtener una referencia a la instancia DriveInfo o DirectoryInfo que el elemento actual representa, y luego obtenemos una lista de directorios secundarios, que agregamos al elemento en el que se hizo clic, una vez más utilizando el método CreateTreeItem () . Observe que el bucle donde agregamos cada carpeta secundaria está en un bloque try..catch; esto es importante porque algunas rutas pueden no ser accesibles, generalmente por razones de seguridad. Usted puede capturar la excepción y usarla para reflejar esto en la interfaz de una forma u otra.
Resumen
Al suscribirse al evento expandido, podemos crear fácilmente un TreeView cargado de forma diferida, que puede ser una solución mucho mejor que una creada estáticamente en varias situaciones.