This article is currently in the process of being translated into Polish (~99% done).
Lazy loading TreeView items
Zwykłym procesem podczas korzystania z TreeView jest powiązanie z kolekcją elementów lub ręczne dodawanie każdego poziomu w tym samym czasie. Jednak w niektórych sytuacjach, chcesz opóźnić ładowanie elementów podrzędnych węzła, dopóki nie będą one rzeczywiście potrzebne. Jest to szczególnie przydatne, jeśli masz bardzo głębokie drzewo, z wieloma poziomami i węzłami podrzędnymi, czego doskonałym przykładem jest struktura folderów komputera z systemem Windows.
Każdy dysk na komputerze z systemem Windows ma szereg folderów podrzędnych, a każdy z tych folderów podrzędnych ma pod sobą foldery podrzędne i tak dalej. Pętla przez każdy dysk i foldery podrzędne każdego dysku może stać się niezwykle czasochłonne, a widok drzewa wkrótce będzie składał się z wielu węzłów, z których wysoki procent z nich nigdy nie byłby potrzebny. Jest to idealne zadanie dla leniwie ładowanego widoku drzewa, w którym foldery podrzędne są ładowane tylko na żądanie.
Aby to osiągnąć, po prostu dodajemy fikcyjny folder do każdego dysku lub folderu podrzędnego, a następnie, gdy użytkownik go rozwinie, usuwamy fikcyjny folder i zastępujemy go rzeczywistymi wartościami. rzeczywistymi wartościami. Tak wygląda nasza aplikacja po uruchomieniu - do tego czasu uzyskaliśmy tylko listę dostępnych dysków na komputerze:
Można teraz rozpocząć rozwijanie węzłów, a aplikacja automatycznie załaduje podfoldery. Jeśli folder jest pusty, zostanie wyświetlony jako pusty po zostanie wyświetlony jako pusty, jak widać na następnym zrzucie ekranu:
Więc jak to się robi? Przyjrzyjmy się kodowi:
<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;
}
}
}
XAML jest bardzo prosty i zawiera tylko jeden interesujący szczegół: Sposób, w jaki subskrybujemy zdarzenie Expanded elementu TreeViewItem. Zauważ że jest to rzeczywiście element TreeViewItem, a nie sam TreeView, ale ponieważ zdarzenie jest wyświetlane, jesteśmy w stanie przechwycić je w jednym miejscu dla całego TreeView. całego TreeView, zamiast subskrybować je dla każdego elementu dodawanego do drzewa. Zdarzenie to jest wywoływane za każdym razem, gdy element jest rozwijany, co musimy musimy być świadomi, aby załadować elementy podrzędne na żądanie.
W Code-behind zaczynamy od dodania każdego dysku znajdującego się na komputerze do kontrolki TreeView. Przypisujemy DriveInfo instancji do właściwości Tag, abyśmy mogli ją później pobrać. Zauważ, że do utworzenia elementu TreeViewItem używamy niestandardowej metody o nazwie CreateTreeItem(), ponieważ możemy użyć dokładnie tej samej metody, gdy chcemy później dynamicznie dodać folder podrzędny. Zauważ w tej metodzie jak dodajemy element podrzędny do kolekcji Items, w postaci ciągu znaków z tekstem "Loading...".
Następne jest zdarzenie TreeViewItem_Expanded. Jak już wspomniano, zdarzenie to jest wywoływane za każdym razem, gdy element TreeView jest rozwijany, więc pierwszą rzeczą, którą robimy, jest sprawdzenie, czy ten element został już załadowany, sprawdzając, czy elementy podrzędne składają się obecnie tylko z jednego elementu, który jest ciągiem znaków - jeśli tak, mamy "Loading...", co oznacza, że powinniśmy teraz załadować rzeczywistą zawartość i zastąpić nią element zastępczy.
Używamy teraz właściwości items Tag, aby uzyskać odniesienie do DriveInfo lub DirectoryInfo którą reprezentuje bieżący element a następnie otrzymujemy listę katalogów podrzędnych, które dodajemy do klikniętego elementu, ponownie używając CreateTreeItem() funkcji. Zauważ, że pętla, w której dodajemy każdy folder podrzędny, znajduje się w bloku try..catch - jest to ważne, ponieważ niektóre ścieżki mogą być niedostępne, zwykle ze względów bezpieczeństwa. ze względów bezpieczeństwa. Można przechwycić wyjątek i użyć go do odzwierciedlenia tego w interfejsie w taki czy inny sposób.
Podsumowanie
Subskrybując zdarzenie Expanded, możemy łatwo utworzyć leniwie ładowany TreeView, który może być znacznie lepszym rozwiązaniem niż statycznie utworzony w kilku sytuacjach. kilku sytuacjach.