This article is currently in the process of being translated into Italian (~97% done).
Caricamento lento degli oggetti TreeView
Il normale processo quando si utilizza TreeView è di associarlo a una raccolta di elementi o di aggiungere manualmente ogni livello. Tuttavia, in alcune situazioni, si desidera ritardare il caricamento degli elementi figlio di un nodo fino a quando non sono effettivamente necessari. Ciò è particolarmente utile se hai un albero molto profondo, con molti livelli e nodi figlio. Un ottimo esempio è la struttura delle cartelle del tuo computer Windows.
Ogni unità sul tuo computer Windows ha cartelle secondarie e ognuna di quelle cartelle secondarie ha cartelle secondarie sotto di esse e così via. Il ciclo attraverso ciascuna unità e ciascuna unità cartelle secondarie potrebbe richiedere molto tempo e il tuo TreeView sarebbe composto da molti nodi, con un'alta percentuale di nodi inutili. Questo è la situazione perfetta dove utilizzare un TreeView a caricamento rallentato, in cui le cartelle secondarie vengono caricate solo su richiesta.
Per ottenere ciò, aggiungiamo semplicemente una cartella fittizia a ciascuna unità o cartella figlio, quindi quando l'utente la espande, rimuoviamo la cartella fittizia e la sostituiamo con i valori effettivi. Ecco come appare la nostra applicazione all'avvio: a quel punto, abbiamo ottenuto solo un elenco di unità disponibili sul computer:
Ora puoi iniziare a espandere i nodi e l'applicazione caricherà automaticamente le sottocartelle. Se una cartella è vuota, verrà mostrata vuota una volta che si tenta di espanderla, come si può vedere nella schermata successiva:
Come viene realizzato? Diamo un'occhiata al codice:
<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;
}
}
}
Il XAML è molto semplice: è presente solo un dettaglio interessante ovvero il modo in cui mettiamo in ascollto dell'evento Expanded di TreeViewItem's. E' un evento di TreeViewItem e non di TreeView stesso, ma siamo in grado di catturarlo in un solo posto per l'intero TreeView, invece di doverlo ascoltare per ogni elemento che aggiungiamo all'albero. Questo evento viene chiamato ogni volta che viene espanso un nodo di cui dobbiamo caricare i suoi figli.
In Code-behind , iniziamo aggiungendo ciascuna unità trovata sul computer al controllo TreeView. Assegniamo il DriveInfo istanza alla proprietà Tag, in modo che possiamo recuperarla in seguito. Si noti che utilizziamo un metodo personalizzato per creare TreeViewItem, chiamato CreateTreeItem () , cosi possiamo utilizzare lo stesso metodo quando vogliamo aggiungere dinamicamente una cartella figlio in un secondo momento. Si noti in questo metodo come aggiungere un elemento figlio alla raccolta Items, sotto forma di una stringa con il testo "Loading...".
Il prossimo è l'evento TreeViewItem_Expanded. Come già accennato, questo evento viene generato ogni volta che un elemento TreeView viene espanso, quindi la prima cosa da fare è verificare se questo elemento è già stato caricato, controllando se gli elementi figlio sono attualmente costituiti da un solo elemento, che è una stringa - in tal caso, abbiamo trovato l'elemento figlio "Caricamento in corso ...", il che significa che ora dovremmo caricare il contenuto effettivo e sostituire l'elemento segnaposto con esso.
Ora utilizziamo la proprietà Tag di items per ottenere un riferimento all'istanza DriveInfo o DirectoryInfo che rappresenta l'elemento corrente e quindi otteniamo un elenco di directory secondarie, che aggiungiamo all'elemento selezionato, ancora una volta utilizzando il metodo CreateTreeItem () . Si noti che il ciclo in cui si aggiunge ogni cartella figlio si trova in un blocco try..catch - questo è importante, perché alcuni percorsi potrebbero non essere accessibili, di solito per ragioni di sicurezza. È possibile catturare l'eccezione e utilizzarla per riflettere questo nell'interfaccia.
Riassunto
Nel sottoscrivere un Expanded event, possiamo facilmente creare una TreeView a caricamento lento, cosa che può essere una soluzione molto migliore che quella statica creata in molte altre situazioni.