Visualizzazione ad albero

La visualizzazione albero abilita un elenco gerarchico con nodi espandibili e comprimibili contenenti elementi annidati. Può essere usato per illustrare una struttura di cartelle o relazioni annidate nell'interfaccia utente.

La visualizzazione albero usa una combinazione di rientri e icone per rappresentare la relazione annidata tra nodi padre e nodi figlio. I nodi compressi usano una freccia di espansione rivolta verso destra, mentre i nodi espansi usano una freccia di espansione rivolta verso il basso.

The chevron icon in TreeView

Puoi includere un'icona nel modello di dati dell'elemento visualizzazione albero per rappresentare i nodi. Se mostri una gerarchia del file system, ad esempio, puoi usare icone di cartella per i nodi padre e icone di file per i nodi foglia.

The chevron and folder icons together in a TreeView

Le API per TreeView supportano le funzionalità seguenti:

  • Nidificazione livello N
  • Selezione di uno o più nodi
  • Associazione di dati alla proprietà ItemsSource in TreeView e TreeViewItem
  • TreeViewItem come radice del modello di elemento TreeView
  • Tipi arbitrari di contenuto in TreeViewItem
  • Trascinamento della selezione tra visualizzazioni albero

È il controllo giusto?

  • Usa un controllo TreeView quando gli elementi includono elementi elenco annidati e se è importante illustrare la relazione gerarchica degli elementi con i relativi peer e nodi.

  • Evita di usare TreeView se non è importante mettere in evidenza la relazione annidata di un elemento. Per la maggior parte degli scenari di drill-in, è sufficiente usare una normale visualizzazione elenco.

Piattaforma UWP e WinUI 2

Importante

Le informazioni e gli esempi in questo articolo sono ottimizzati per le app che usano Windows App SDK e WinUI 3, ma sono generalmente applicabili alle app UWP che usano WinUI 2. Per informazioni ed esempi specifici della piattaforma, consultare le indicazioni di riferimento sulle API UWP.

Questa sezione contiene informazioni necessarie per usare il controllo in un'app UWP o WinUI 2.

TreeView per le app UWP è incluso come parte della libreria dell'interfaccia utente di Windows 2. Per altre informazioni, incluse le istruzioni per l'installazione, vedi Libreria dell'interfaccia utente di Windows. Le API per questo controllo sono presenti negli spazi dei nomi Windows.UI.Xaml.Controls (UWP) e Microsoft.UI.Xaml.Controls (WinUI).

È consigliabile usare la versione più recente di WinUI 2 per ottenere gli stili, i modelli e le funzionalità più recenti per tutti i controlli.

Per usare il codice in questo articolo con WinUI 2, usare un alias in XAML (si usa muxc) per rappresentare le API della libreria dell'interfaccia utente di Windows incluse nel progetto. Per altre informazioni, vedere Attività iniziali di WinUI 2.

xmlns:muxc="using:Microsoft.UI.Xaml.Controls"

<muxc:TreeView>
    <muxc:TreeView.RootNodes>
        <muxc:TreeViewNode Content="Flavors">
            <muxc:TreeViewNode.Children>
                <muxc:TreeViewNode Content="Vanilla"/>
            </muxc:TreeViewNode.Children>
        </muxc:TreeViewNode>
    </muxc:TreeView.RootNodes>
</muxc:TreeView>

Creare una visualizzazione albero

Puoi creare una visualizzazione albero associando ItemsSource a un'origine dati gerarchica oppure creare e gestire personalmente oggetti TreeViewNode.

Per creare una visualizzazione albero, usa un controllo TreeView e una gerarchia di oggetti TreeViewNode. Crea la gerarchia di nodi aggiungendo uno o più nodi radice alla raccolta TreeView del controllo RootNodes. Alla raccolta Children di ogni oggetto TreeViewNode possono quindi essere aggiunti più nodi. Puoi annidare nodi della visualizzazione albero a qualsiasi profondità.

Puoi associare un'origine dati gerarchica alla proprietà ItemsSource per specificare il contenuto della visualizzazione albero, così come con la proprietà ItemsSource di ListView. Analogamente, usa ItemTemplate e il parametro facoltativo ItemTemplateSelector per specificare un DataTemplate per il rendering dell'elemento.

Importante

ItemsSource e le API correlate richiedono Windows 10 versione 1809 (SDK 17763) o successiva oppure la libreria dell'interfaccia utente di Windows.

ItemsSource è un meccanismo alternativo a TreeView.RootNodes per inserire contenuto nel controllo TreeView. Non puoi impostare contemporaneamente sia ItemsSource che RootNodes. Quando usi ItemsSource, i nodi vengono creati automaticamente e puoi accedervi dalla proprietà TreeView.RootNodes.

Ecco un esempio di visualizzazione albero semplice dichiarata in XAML. In genere i nodi vengono aggiunti nel codice, ma qui mostriamo la gerarchia XAML perché può essere utile per visualizzare come viene creata la gerarchia di nodi.

<muxc:TreeView>
    <muxc:TreeView.RootNodes>
        <muxc:TreeViewNode Content="Flavors"
                           IsExpanded="True">
            <muxc:TreeViewNode.Children>
                <muxc:TreeViewNode Content="Vanilla"/>
                <muxc:TreeViewNode Content="Strawberry"/>
                <muxc:TreeViewNode Content="Chocolate"/>
            </muxc:TreeViewNode.Children>
        </muxc:TreeViewNode>
    </muxc:TreeView.RootNodes>
</muxc:TreeView>

Nella maggior parte dei casi, la visualizzazione albero mostra i dati da un'origine dati, quindi in genere dichiari il controllo TreeView radice in XAML, ma aggiungi gli oggetti TreeViewNode nel codice o usando un'associazione di dati.

Eseguire l'associazione a un'origine dati gerarchica

Per creare una visualizzazione albero usando un'associazione di dati, imposta la proprietà TreeView.ItemsSource su una raccolta gerarchica. In ItemTemplate imposta quindi la proprietà TreeViewItem.ItemsSource sulla raccolta di elementi figlio.

<muxc:TreeView ItemsSource="{x:Bind DataSource}">
    <muxc:TreeView.ItemTemplate>
        <DataTemplate x:DataType="local:Item">
            <muxc:TreeViewItem ItemsSource="{x:Bind Children}"
                               Content="{x:Bind Name}"/>
        </DataTemplate>
    </muxc:TreeView.ItemTemplate>
</muxc:TreeView>

Per il codice completo, vedi Visualizzazione albero con associazione di dati.

Elementi e contenitori di elementi

Se usi TreeView.ItemsSource, per ottenere il nodo o l'elemento di dati dal contenitore e viceversa sono disponibili queste API.

TreeViewItem Descrizione
TreeView.ItemFromContainer Ottiene l'elemento di dati per il contenitore TreeViewItem specificato.
TreeView.ContainerFromItem Ottiene il contenitore TreeViewItem per l'elemento di dati specificato.
TreeViewNode Descrizione
TreeView.NodeFromContainer Ottiene l'oggetto TreeViewNode per il contenitore TreeViewItem specificato.
TreeView.ContainerFromNode Ottiene il contenitore TreeViewItem per l'oggetto TreeViewNode specificato.

Gestire i nodi della visualizzazione albero

Questa visualizzazione albero è uguale a quella creata in precedenza in XAML, ma i nodi vengono creati nel codice.

<muxc:TreeView x:Name="sampleTreeView"/>
private void InitializeTreeView()
{
    muxc.TreeViewNode rootNode = new muxc.TreeViewNode() { Content = "Flavors" };
    rootNode.IsExpanded = true;
    rootNode.Children.Add(new muxc.TreeViewNode() { Content = "Vanilla" });
    rootNode.Children.Add(new muxc.TreeViewNode() { Content = "Strawberry" });
    rootNode.Children.Add(new muxc.TreeViewNode() { Content = "Chocolate" });

    sampleTreeView.RootNodes.Add(rootNode);
}
Private Sub InitializeTreeView()
    Dim rootNode As New muxc.TreeViewNode With {.Content = "Flavors", .IsExpanded = True}
    With rootNode.Children
        .Add(New muxc.TreeViewNode With {.Content = "Vanilla"})
        .Add(New muxc.TreeViewNode With {.Content = "Strawberry"})
        .Add(New muxc.TreeViewNode With {.Content = "Chocolate"})
    End With
    sampleTreeView.RootNodes.Add(rootNode)
End Sub

Per la gestione della gerarchia di dati della visualizzazione albero sono disponibili queste API.

TreeView Descrizione
RootNodes Una visualizzazione albero può contenere uno o più nodi radice. Per creare un nodo radice, aggiungi un oggetto TreeViewNode alla raccolta RootNodes. Per un nodo radice, il valore di Parent è sempre null e il valore di Depth è 0.
TreeViewNode Descrizione
Children Per creare la gerarchia di nodi, aggiungi oggetti TreeViewNode alla raccolta Children di un nodo padre. Un nodo è il nodo Parent di tutti i nodi nella relativa raccolta Children.
HasChildren true se il nodo contiene elementi figlio realizzati. false indica una cartella vuota o un elemento.
HasUnrealizedChildren Usa questa proprietà se completi i nodi quando vengono espansi. Vedi Completare un nodo durante l'espansione più avanti in questo articolo.
Livello di annidamento Indica la distanza tra un nodo figlio e il nodo radice.
Parent Ottiene il nodo TreeViewNode proprietario della raccolta Children di cui fa parte il nodo.

La visualizzazione albero usa le proprietà HasChildren e HasUnrealizedChildren per determinare se verrà visualizzata l'icona di espansione/compressione. Se una delle due proprietà è true, l'icona viene visualizzata. In caso contrario, non viene visualizzata.

Contenuto di un nodo della visualizzazione albero

Puoi archiviare l'elemento di dati rappresentato da un nodo della visualizzazione albero nella relativa proprietà Content.

Negli esempi precedenti il contenuto è un semplice valore stringa. In questo esempio, un nodo della visualizzazione albero rappresenta la cartella Pictures dell'utente, quindi alla proprietà Content del nodo viene assegnato l'oggetto StorageFolder della raccolta Pictures.

StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
muxc.TreeViewNode pictureNode = new muxc.TreeViewNode();
pictureNode.Content = picturesFolder;
Dim picturesFolder As StorageFolder = KnownFolders.PicturesLibrary
Dim pictureNode As New muxc.TreeViewNode With {.Content = picturesFolder}

Nota

Per ottenere l'accesso alla cartella Pictures, devi specificare la funzionalità Pictures Library nel manifesto dell'app. Per ulteriori informazioni, vedere Dichiarazioni di funzionalità delle app.

Per specificare come l'elemento di dati deve essere visualizzato nella visualizzazione albero, puoi fornire un oggetto DataTemplate.

Nota

In Windows 10 versione 1803, se il contenuto non è una stringa, devi ridefinire il modello del controllo TreeView e specificare un oggetto ItemTemplate personalizzato. Nelle versioni successive devi impostare la proprietà ItemTemplate. Per altre informazioni, vedi TreeView.ItemTemplate.

Stile del contenitore dell'elemento

Indipendentemente dall'uso di ItemsSource o RootNodes, l'elemento effettivamente usato per visualizzare ogni nodo, detto "contenitore", è un oggetto TreeViewItem. Puoi modificare le proprietà TreeViewItem per definire lo stile del contenitore usando la proprietà ItemContainerStyle o ItemContainerStyleSelector di TreeView.

Questo esempio mostra come modificare i glifi espansi/compressi in segni +/- di colore arancione. Nel modello TreeViewItem predefinito i glifi sono impostati in modo da usare il tipo di carattere Segoe MDL2 Assets. Puoi impostare la proprietà Setter.Value specificando il valore del carattere Unicode nel formato usato da XAML, ad esempio: Value="&#xE948;".

<muxc:TreeView>
    <muxc:TreeView.ItemContainerStyle>
        <Style TargetType="muxc:TreeViewItem">
            <Setter Property="CollapsedGlyph" Value="&#xE948;"/>
            <Setter Property="ExpandedGlyph" Value="&#xE949;"/>
            <Setter Property="GlyphBrush" Value="DarkOrange"/>
        </Style>
    </muxc:TreeView.ItemContainerStyle>
    <muxc:TreeView.RootNodes>
        <muxc:TreeViewNode Content="Flavors"
               IsExpanded="True">
            <muxc:TreeViewNode.Children>
                <muxc:TreeViewNode Content="Vanilla"/>
                <muxc:TreeViewNode Content="Strawberry"/>
                <muxc:TreeViewNode Content="Chocolate"/>
            </muxc:TreeViewNode.Children>
        </muxc:TreeViewNode>
    </muxc:TreeView.RootNodes>
</muxc:TreeView>

Selettori del modello di elemento

Per impostazione predefinita, TreeView mostra la rappresentazione di stringa dell'elemento di dati per ogni nodo. Puoi impostare la proprietà ItemTemplate per modificare gli elementi visualizzati per tutti i nodi. In alternativa, puoi usare un oggetto ItemTemplateSelector per scegliere un oggetto DataTemplate diverso per gli elementi della visualizzazione struttura ad albero in base al tipo di elemento o ad altri criteri specificati.

In un'app di esplorazione file, ad esempio, potresti usare un modello di dati per le cartelle e un altro per i file.

Folders and files using different data templates

Di seguito è riportato un esempio di come creare e usare un selettore del modello di elemento. Per altre informazioni, vedi la classe DataTemplateSelector.

Nota

Questo codice fa parte di un esempio più ampio e non funzionerà autonomamente. Per vedere l'esempio completo, incluso il codice che definisce ExplorerItem, consulta il repository Xaml-Controls-Gallery su GitHub. TreeViewPage.xaml e TreeViewPage.xaml.cs contengono il codice pertinente.

<Page.Resources>
    <DataTemplate x:Key="FolderTemplate" x:DataType="local:ExplorerItem">
        <muxc:TreeViewItem ItemsSource="{x:Bind Children}">
            <StackPanel Orientation="Horizontal">
                <Image Width="20" Source="Assets/folder.png"/>
                <TextBlock Text="{x:Bind Name}" />
            </StackPanel>
        </muxc:TreeViewItem>
    </DataTemplate>

    <DataTemplate x:Key="FileTemplate" x:DataType="local:ExplorerItem">
        <muxc:TreeViewItem>
            <StackPanel Orientation="Horizontal">
                <Image Width="20" Source="Assets/file.png"/>
                <TextBlock Text="{x:Bind Name}"/>
            </StackPanel>
        </muxc:TreeViewItem>
    </DataTemplate>

    <local:ExplorerItemTemplateSelector
            x:Key="ExplorerItemTemplateSelector"
            FolderTemplate="{StaticResource FolderTemplate}"
            FileTemplate="{StaticResource FileTemplate}" />
</Page.Resources>

<Grid>
    <muxc:TreeView
        ItemsSource="{x:Bind DataSource}"
        ItemTemplateSelector="{StaticResource ExplorerItemTemplateSelector}"/>
</Grid>
public class ExplorerItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate FolderTemplate { get; set; }
    public DataTemplate FileTemplate { get; set; }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        var explorerItem = (ExplorerItem)item;
        if (explorerItem.Type == ExplorerItem.ExplorerItemType.Folder) return FolderTemplate;

        return FileTemplate;
    }
}

Il tipo di oggetto passato al metodo SelectTemplateCore varia a seconda che si crei la visualizzazione struttura ad albero impostando la proprietà ItemsSource oppure creando e gestendo gli oggetti TreeViewNode autonomamente.

  • Se è impostato ItemsSource, l'oggetto sarà dello stesso tipo dell'elemento di dati. Nell'esempio precedente l'oggetto è ExplorerItem e quindi può essere usato dopo un semplice cast in ExplorerItem: var explorerItem = (ExplorerItem)item;.
  • Se non è impostato ItemsSource e gestisci i nodi della visualizzazione struttura ad albero autonomamente, l'oggetto passato a SelectTemplateCore è TreeViewNode. In questo caso puoi ottenere l'elemento di dati dalla proprietà TreeViewNode.Content.

Di seguito è riportato un selettore del modello di dati dell'esempio Visualizzazione albero delle raccolte Pictures e Music riportato più avanti. Il metodo SelectTemplateCore riceve un oggetto TreeViewNode, che può avere StorageFolder o StorageFile come contenuto. In base al contenuto, puoi restituire un modello predefinito o un modello specifico per la cartella Music, la cartella Pictures, i file musicali o i file di immagine.

protected override DataTemplate SelectTemplateCore(object item)
{
    var node = (TreeViewNode)item;
    if (node.Content is StorageFolder)
    {
        var content = node.Content as StorageFolder;
        if (content.DisplayName.StartsWith("Pictures")) return PictureFolderTemplate;
        if (content.DisplayName.StartsWith("Music")) return MusicFolderTemplate;
    }
    else if (node.Content is StorageFile)
    {
        var content = node.Content as StorageFile;
        if (content.ContentType.StartsWith("image")) return PictureItemTemplate;
        if (content.ContentType.StartsWith("audio")) return MusicItemTemplate;
    }
    return DefaultTemplate;
}
Protected Overrides Function SelectTemplateCore(ByVal item As Object) As DataTemplate
    Dim node = CType(item, muxc.TreeViewNode)

    If TypeOf node.Content Is StorageFolder Then
        Dim content = TryCast(node.Content, StorageFolder)
        If content.DisplayName.StartsWith("Pictures") Then Return PictureFolderTemplate
        If content.DisplayName.StartsWith("Music") Then Return MusicFolderTemplate
    ElseIf TypeOf node.Content Is StorageFile Then
        Dim content = TryCast(node.Content, StorageFile)
        If content.ContentType.StartsWith("image") Then Return PictureItemTemplate
        If content.ContentType.StartsWith("audio") Then Return MusicItemTemplate
    End If

    Return DefaultTemplate
End Function

Interazione con una visualizzazione albero

Puoi configurare una visualizzazione albero per consentire all'utente di interagirvi in diversi modi:

  • Espandere o comprimere i nodi
  • Selezionare uno o più elementi
  • Fare clic per richiamare un elemento

Espandi/comprimi

Qualsiasi nodo della visualizzazione albero con elementi figlio può sempre essere espanso o compresso facendo clic sul glifo di espansione/compressione. Puoi anche espandere o comprimere un nodo a livello di codice e rispondere al cambiamento di stato di un nodo.

Espandere/comprimere un nodo a livello di codice

Per espandere o comprimere un nodo della visualizzazione albero nel codice sono disponibili 2 modi.

  • La classe TreeView include i metodi Collapse ed Expand. Quando chiami questi metodi, passi l'oggetto TreeViewNode da espandere o comprimere.

  • Ogni TreeViewNode ha la proprietà IsExpanded. Puoi usare questa proprietà per controllare lo stato di un nodo o impostarla per modificare lo stato. Puoi anche impostare questa proprietà in XAML per impostare lo stato iniziale di un nodo.

Completare un nodo durante l'espansione

Potrebbe essere necessario mostrare un numero elevato di nodi nella visualizzazione albero oppure potresti non sapere in anticipo quanti nodi saranno presenti. Poiché il controllo TreeView non è virtualizzato, puoi gestire le risorse completando ogni nodo mentre viene espanso e rimuovendo i nodi figlio quando viene compresso.

Gestisci l'evento Expanding e usa la proprietà HasUnrealizedChildren per aggiungere elementi figlio a un nodo quando viene espanso. La proprietà HasUnrealizedChildren indica se il nodo deve essere completato o se la raccolta Children è già stata popolata. È importante tenere presente che TreeViewNode non imposta questo valore, che deve essere gestito nel codice dell'app.

Di seguito è riportato un esempio dell'uso di queste API. Per il contesto, inclusa l'implementazione di FillTreeNode, vedi il codice di esempio completo alla fine di questo articolo.

private void SampleTreeView_Expanding(muxc.TreeView sender, muxc.TreeViewExpandingEventArgs args)
{
    if (args.Node.HasUnrealizedChildren)
    {
        FillTreeNode(args.Node);
    }
}
Private Sub SampleTreeView_Expanding(sender As muxc.TreeView, args As muxc.TreeViewExpandingEventArgs)
    If args.Node.HasUnrealizedChildren Then
        FillTreeNode(args.Node)
    End If
End Sub

Anche se non è obbligatorio, potrebbe essere opportuno anche gestire l'evento Collapsed e rimuovere i nodi figlio quando il nodo padre è chiuso. Può essere importante se la visualizzazione albero contiene molti nodi o se i dati del nodo usano una quantità elevata di risorse. È consigliabile valutare l'impatto sulle prestazioni del completamento di un nodo ogni volta che viene aperto o del mantenimento degli elementi figlio in un nodo chiuso. L'opzione migliore dipenderà dalla tua app.

Di seguito è riportato un esempio di gestore per l'evento Collapsed.

private void SampleTreeView_Collapsed(muxc.TreeView sender, muxc.TreeViewCollapsedEventArgs args)
{
    args.Node.Children.Clear();
    args.Node.HasUnrealizedChildren = true;
}
Private Sub SampleTreeView_Collapsed(sender As muxc.TreeView, args As muxc.TreeViewCollapsedEventArgs)
    args.Node.Children.Clear()
    args.Node.HasUnrealizedChildren = True
End Sub

Chiamata di un elemento

Invece di selezionare l'elemento, l'utente può richiamare un'azione, trattando così l'elemento come un pulsante. Per rispondere a questa interazione dell'utente, gestisci l'evento ItemInvoked.

Nota

A differenza di ListView, che ha la proprietà IsItemClickEnabled, la chiamata di un elemento è sempre abilitata nella visualizzazione albero. Puoi comunque scegliere se gestire o meno l'evento.

Classe TreeViewItemInvokedEventArgs

Gli argomenti dell'evento ItemInvoked consentono di accedere all'elemento richiamato. La proprietà InvokedItem contiene il nodo richiamato. Puoi eseguirne il cast in TreeViewNode e ottenere l'elemento di dati dalla proprietà TreeViewNode.Content.

Di seguito è riportato un esempio di gestore per l'evento ItemInvoked. L'elemento di dati è di tipo IStorageItem e questo esempio visualizza solo alcune informazioni sul file e sull'albero. Se il nodo è un nodo cartella, inoltre, viene contemporaneamente espanso o compresso. In caso contrario, il nodo viene espanso o compresso solo facendo clic sulla freccia di espansione.

private void SampleTreeView_ItemInvoked(muxc.TreeView sender, muxc.TreeViewItemInvokedEventArgs args)
{
    var node = args.InvokedItem as muxc.TreeViewNode;
    if (node.Content is IStorageItem item)
    {
        FileNameTextBlock.Text = item.Name;
        FilePathTextBlock.Text = item.Path;
        TreeDepthTextBlock.Text = node.Depth.ToString();

        if (node.Content is StorageFolder)
        {
            node.IsExpanded = !node.IsExpanded;
        }
    }
}
Private Sub SampleTreeView_ItemInvoked(sender As muxc.TreeView, args As muxc.TreeViewItemInvokedEventArgs)
    Dim node = TryCast(args.InvokedItem, muxc.TreeViewNode)
    Dim item = TryCast(node.Content, IStorageItem)
    If item IsNot Nothing Then
        FileNameTextBlock.Text = item.Name
        FilePathTextBlock.Text = item.Path
        TreeDepthTextBlock.Text = node.Depth.ToString()
        If TypeOf node.Content Is StorageFolder Then
            node.IsExpanded = Not node.IsExpanded
        End If
    End If
End Sub

Selezione degli elementi

Il controllo TreeView supporta sia la selezione singola che la selezione multipla. Per impostazione predefinita, la selezione dei nodi è disabilitata, ma puoi impostare la proprietà TreeView.SelectionMode per consentirla. I valori di TreeViewSelectionMode sono None, Single e Multiple.

Selezione multipla

Quando è abilitata la selezione multipla, viene visualizzata una casella di controllo accanto a ogni nodo della visualizzazione albero e gli elementi selezionati sono evidenziati. L'utente può selezionare o deselezionare un elemento usando la casella di controllo. Se fa clic sull'elemento, lo richiama.

Selezionando o deselezionando un nodo padre verranno selezionati o deselezionati tutti gli elementi figlio sottostanti. Se vengono selezionati alcuni elementi figlio di un nodo padre ma non tutti, la casella di controllo del nodo padre viene visualizzata nello stato indeterminato.

Multiple selection in a tree view

I nodi selezionati vengono aggiunti alla raccolta SelectedNodes della visualizzazione albero. Puoi chiamare il metodo SelectAll per selezionare tutti i nodi in una visualizzazione albero.

Nota

Se chiami SelectAll vengono selezionati tutti i nodi realizzati, indipendentemente da SelectionMode. Per offrire un'esperienza utente coerente, è consigliabile chiamareSelectAll solo se il valore di SelectionMode è Multiple.

Selezione e nodi realizzati/non realizzati

Se la visualizzazione albero contiene nodi non realizzati, non vengono presi in considerazione ai fini della selezione. In relazione alla selezione con nodi non realizzati è necessario tenere presenti gli aspetti seguenti:

  • Se un utente seleziona un nodo padre, vengono selezionati anche tutti i nodi figlio realizzati sottostanti. Analogamente, se vengono selezionati tutti i nodi figlio, viene selezionato anche il nodo padre.
  • Il metodo SelectAll aggiunge solo i nodi realizzati alla raccolta SelectedNodes.
  • Se viene selezionato un nodo padre con nodi figlio non realizzati, questi verranno selezionati nel momento in cui vengono realizzati.

SelectedItem/SelectedItems

TreeView presenta le proprietà SelectedItem e SelectedItems. Puoi usare queste proprietà per ottenere direttamente il contenuto dei nodi selezionati. Se è abilitata la selezione multipla, SelectedItem contiene il primo elemento nella raccolta SelectedItems.

SelectionChanged

È possibile gestire l'evento SelectionChanged per rispondere quando cambia la raccolta di elementi selezionati, a livello di codice o tramite l'interazione dell'utente.

<TreeView ItemsSource="{x:Bind Folders}"
          SelectionMode="Multiple"
          SelectionChanged="TreeView_SelectionChanged"/>
public void TreeView_SelectionChanged(TreeView sender, TreeViewSelectionChangedEventArgs args)
{
    foreach (object item in args.RemovedItems)
    {
        this.SelectedFolders.Remove((Folder)item);
    }

    foreach (object item in args.AddedItems)
    {
        this.SelectedFolders.Add((Folder)item);
    }
}

Esempi di codice

Gli esempi di codice seguenti illustrano diverse caratteristiche del controllo di visualizzazione albero.

Visualizzazione albero con XAML

Questo esempio mostra come creare la struttura di una visualizzazione albero semplice in XAML. La visualizzazione albero mostra i gusti e le guarnizioni di gelato che l'utente può scegliere, disposti in categorie. La selezione multipla è abilitata e quando l'utente fa clic su un pulsante vengono visualizzati gli elementi selezionati nell'interfaccia utente principale dell'app.

<Page
    x:Class="TreeViewTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
          Padding="100">
        <SplitView IsPaneOpen="True"
               DisplayMode="Inline"
               OpenPaneLength="296">
            <SplitView.Pane>
                <muxc:TreeView x:Name="DessertTree" SelectionMode="Multiple">
                    <muxc:TreeView.RootNodes>
                        <muxc:TreeViewNode Content="Flavors" IsExpanded="True">
                            <muxc:TreeViewNode.Children>
                                <muxc:TreeViewNode Content="Vanilla"/>
                                <muxc:TreeViewNode Content="Strawberry"/>
                                <muxc:TreeViewNode Content="Chocolate"/>
                            </muxc:TreeViewNode.Children>
                        </muxc:TreeViewNode>

                        <muxc:TreeViewNode Content="Toppings">
                            <muxc:TreeViewNode.Children>
                                <muxc:TreeViewNode Content="Candy">
                                    <muxc:TreeViewNode.Children>
                                        <muxc:TreeViewNode Content="Chocolate"/>
                                        <muxc:TreeViewNode Content="Mint"/>
                                        <muxc:TreeViewNode Content="Sprinkles"/>
                                    </muxc:TreeViewNode.Children>
                                </muxc:TreeViewNode>
                                <muxc:TreeViewNode Content="Fruits">
                                    <muxc:TreeViewNode.Children>
                                        <muxc:TreeViewNode Content="Mango"/>
                                        <muxc:TreeViewNode Content="Peach"/>
                                        <muxc:TreeViewNode Content="Kiwi"/>
                                    </muxc:TreeViewNode.Children>
                                </muxc:TreeViewNode>
                                <muxc:TreeViewNode Content="Berries">
                                    <muxc:TreeViewNode.Children>
                                        <muxc:TreeViewNode Content="Strawberry"/>
                                        <muxc:TreeViewNode Content="Blueberry"/>
                                        <muxc:TreeViewNode Content="Blackberry"/>
                                    </muxc:TreeViewNode.Children>
                                </muxc:TreeViewNode>
                            </muxc:TreeViewNode.Children>
                        </muxc:TreeViewNode>
                    </muxc:TreeView.RootNodes>
                </muxc:TreeView>
            </SplitView.Pane>

            <StackPanel Grid.Column="1" Margin="12,0">
                <Button Content="Select all" Click="SelectAllButton_Click"/>
                <Button Content="Create order" Click="OrderButton_Click" Margin="0,12"/>
                <TextBlock Text="Your flavor selections:" Style="{StaticResource CaptionTextBlockStyle}"/>
                <TextBlock x:Name="FlavorList" Margin="0,0,0,12"/>
                <TextBlock Text="Your topping selections:" Style="{StaticResource CaptionTextBlockStyle}"/>
                <TextBlock x:Name="ToppingList"/>
            </StackPanel>
        </SplitView>
    </Grid>
</Page>
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using muxc = Microsoft.UI.Xaml.Controls;

namespace TreeViewTest
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private void OrderButton_Click(object sender, RoutedEventArgs e)
        {
            FlavorList.Text = string.Empty;
            ToppingList.Text = string.Empty;

            foreach (muxc.TreeViewNode node in DessertTree.SelectedNodes)
            {
                if (node.Parent.Content?.ToString() == "Flavors")
                {
                    FlavorList.Text += node.Content + "; ";
                }
                else if (node.HasChildren == false)
                {
                    ToppingList.Text += node.Content + "; ";
                }
            }
        }

        private void SelectAllButton_Click(object sender, RoutedEventArgs e)
        {
            if (DessertTree.SelectionMode == muxc.TreeViewSelectionMode.Multiple)
            {
                DessertTree.SelectAll();
            }
        }
    }
}
Private Sub OrderButton_Click(sender As Object, e As RoutedEventArgs)
    FlavorList.Text = String.Empty
    ToppingList.Text = String.Empty
    For Each node As muxc.TreeViewNode In DessertTree.SelectedNodes
        If node.Parent.Content?.ToString() = "Flavors" Then
            FlavorList.Text += node.Content & "; "
        ElseIf node.HasChildren = False Then
            ToppingList.Text += node.Content & "; "
        End If
    Next
End Sub

Private Sub SelectAllButton_Click(sender As Object, e As RoutedEventArgs)
    If DessertTree.SelectionMode = muxc.TreeViewSelectionMode.Multiple Then
        DessertTree.SelectAll()
    End If
End Sub

Visualizzazione albero con associazione di dati

Questo esempio mostra come creare la stessa visualizzazione albero dell'esempio precedente. Invece di creare la gerarchia di dati in XAML, i dati vengono però creati nel codice e associati alla proprietà ItemsSource della visualizzazione albero. I gestori eventi dei pulsanti illustrati nell'esempio precedente si applicano anche a questo esempio.

<Page
    x:Class="TreeViewTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
    xmlns:local="using:TreeViewTest"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
          Padding="100">
        <SplitView IsPaneOpen="True"
                   DisplayMode="Inline"
                   OpenPaneLength="296">
            <SplitView.Pane>
                <muxc:TreeView Name="DessertTree"
                                      SelectionMode="Multiple"
                                      ItemsSource="{x:Bind DataSource}">
                    <muxc:TreeView.ItemTemplate>
                        <DataTemplate x:DataType="local:Item">
                            <muxc:TreeViewItem
                                ItemsSource="{x:Bind Children}"
                                Content="{x:Bind Name}"/>
                        </DataTemplate>
                    </muxc:TreeView.ItemTemplate>
                </muxc:TreeView>
            </SplitView.Pane>

            <StackPanel Grid.Column="1" Margin="12,0">
                <Button Content="Select all"
                        Click="SelectAllButton_Click"/>
                <Button Content="Create order"
                        Click="OrderButton_Click"
                        Margin="0,12"/>
                <TextBlock Text="Your flavor selections:"
                           Style="{StaticResource CaptionTextBlockStyle}"/>
                <TextBlock x:Name="FlavorList" Margin="0,0,0,12"/>
                <TextBlock Text="Your topping selections:"
                           Style="{StaticResource CaptionTextBlockStyle}"/>
                <TextBlock x:Name="ToppingList"/>
            </StackPanel>
        </SplitView>
    </Grid>

</Page>
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using muxc = Microsoft.UI.Xaml.Controls;

namespace TreeViewTest
{
    public sealed partial class MainPage : Page
    {
        private ObservableCollection<Item> DataSource = new ObservableCollection<Item>();

        public MainPage()
        {
            this.InitializeComponent();
            DataSource = GetDessertData();
        }

        private ObservableCollection<Item> GetDessertData()
        {
            var list = new ObservableCollection<Item>();

            Item flavorsCategory = new Item()
            {
                Name = "Flavors",
                Children =
                {
                    new Item() { Name = "Vanilla" },
                    new Item() { Name = "Strawberry" },
                    new Item() { Name = "Chocolate" }
                }
            };

            Item toppingsCategory = new Item()
            {
                Name = "Toppings",
                Children =
                {
                    new Item()
                    {
                        Name = "Candy",
                        Children =
                        {
                            new Item() { Name = "Chocolate" },
                            new Item() { Name = "Mint" },
                            new Item() { Name = "Sprinkles" }
                        }
                    },
                    new Item()
                    {
                        Name = "Fruits",
                        Children =
                        {
                            new Item() { Name = "Mango" },
                            new Item() { Name = "Peach" },
                            new Item() { Name = "Kiwi" }
                        }
                    },
                    new Item()
                    {
                        Name = "Berries",
                        Children =
                        {
                            new Item() { Name = "Strawberry" },
                            new Item() { Name = "Blueberry" },
                            new Item() { Name = "Blackberry" }
                        }
                    }
                }
            };

            list.Add(flavorsCategory);
            list.Add(toppingsCategory);
            return list;
        }

        private void OrderButton_Click(object sender, RoutedEventArgs e)
        {
            FlavorList.Text = string.Empty;
            ToppingList.Text = string.Empty;

            foreach (muxc.TreeViewNode node in DessertTree.SelectedNodes)
            {
                if (node.Parent.Content?.ToString() == "Flavors")
                {
                    FlavorList.Text += node.Content + "; ";
                }
                else if (node.HasChildren == false)
                {
                    ToppingList.Text += node.Content + "; ";
                }
            }
        }

        private void SelectAllButton_Click(object sender, RoutedEventArgs e)
        {
            if (DessertTree.SelectionMode == muxc.TreeViewSelectionMode.Multiple)
            {
                DessertTree.SelectAll();
            }
        }
    }

    public class Item
    {
        public string Name { get; set; }
        public ObservableCollection<Item> Children { get; set; } = new ObservableCollection<Item>();

        public override string ToString()
        {
            return Name;
        }
    }
}

Visualizzazione albero delle raccolte Pictures e Music

Questo esempio illustra come creare una visualizzazione albero che mostra il contenuto e la struttura delle raccolte Pictures e Music degli utenti. Dato che non è possibile conoscere in anticipo il numero di elementi, ogni nodo viene completato quando viene espanso e svuotato quando viene compresso.

Per visualizzare gli elementi di dati, che sono di tipo IStorageItem, viene usato un modello di elemento personalizzato.

Importante

Il codice in questo esempio richiede le funzionalità picturesLibrary e musicLibrary. Per altre informazioni sull'accesso ai file, vedi Autorizzazioni di accesso ai file, Enumerare file e cartelle ed eseguire query su di essi e File e cartelle nelle raccolte Musica, Immagini e Video.

<Page
    x:Class="TreeViewTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TreeViewTest"
    xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
    xmlns:storage="using:Windows.Storage"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <DataTemplate x:Key="TreeViewItemDataTemplate" x:DataType="muxc:TreeViewNode">
            <Grid Height="44">
                <TextBlock Text="{x:Bind ((storage:IStorageItem)Content).Name}"
                           HorizontalAlignment="Left"
                           VerticalAlignment="Center"
                           Style="{ThemeResource BodyTextBlockStyle}"/>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="MusicItemDataTemplate" x:DataType="muxc:TreeViewNode">
            <StackPanel Height="44" Orientation="Horizontal">
                <SymbolIcon Symbol="Audio" Margin="0,0,4,0"/>
                <TextBlock Text="{x:Bind ((storage:StorageFile)Content).DisplayName}"
                           HorizontalAlignment="Left"
                           VerticalAlignment="Center"
                           Style="{ThemeResource BodyTextBlockStyle}"/>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="PictureItemDataTemplate" x:DataType="muxc:TreeViewNode">
            <StackPanel Height="44" Orientation="Horizontal">
                <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xEB9F;"
                          Margin="0,0,4,0"/>
                <TextBlock Text="{x:Bind ((storage:StorageFile)Content).DisplayName}"
                           HorizontalAlignment="Left"
                           VerticalAlignment="Center"
                           Style="{ThemeResource BodyTextBlockStyle}"/>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="MusicFolderDataTemplate" x:DataType="muxc:TreeViewNode">
            <StackPanel Height="44" Orientation="Horizontal">
                <SymbolIcon Symbol="MusicInfo" Margin="0,0,4,0"/>
                <TextBlock Text="{x:Bind ((storage:StorageFolder)Content).DisplayName}"
                           HorizontalAlignment="Left"
                           VerticalAlignment="Center"
                           Style="{ThemeResource BodyTextBlockStyle}"/>
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="PictureFolderDataTemplate" x:DataType="muxc:TreeViewNode">
            <StackPanel Height="44" Orientation="Horizontal">
                <SymbolIcon Symbol="Pictures" Margin="0,0,4,0"/>
                <TextBlock Text="{x:Bind ((storage:StorageFolder)Content).DisplayName}"
                           HorizontalAlignment="Left"
                           VerticalAlignment="Center"
                           Style="{ThemeResource BodyTextBlockStyle}"/>
            </StackPanel>
        </DataTemplate>

        <local:ExplorerItemTemplateSelector
            x:Key="ExplorerItemTemplateSelector"
            DefaultTemplate="{StaticResource TreeViewItemDataTemplate}"
            MusicItemTemplate="{StaticResource MusicItemDataTemplate}"
            MusicFolderTemplate="{StaticResource MusicFolderDataTemplate}"
            PictureItemTemplate="{StaticResource PictureItemDataTemplate}"
            PictureFolderTemplate="{StaticResource PictureFolderDataTemplate}"/>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <SplitView IsPaneOpen="True"
                   DisplayMode="Inline"
                   OpenPaneLength="296">
            <SplitView.Pane>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Button Content="Refresh tree" Click="RefreshButton_Click" Margin="24,12"/>
                    <muxc:TreeView x:Name="sampleTreeView" Grid.Row="1" SelectionMode="Single"
                              ItemTemplateSelector="{StaticResource ExplorerItemTemplateSelector}"
                              Expanding="SampleTreeView_Expanding"
                              Collapsed="SampleTreeView_Collapsed"
                              ItemInvoked="SampleTreeView_ItemInvoked"/>
                </Grid>
            </SplitView.Pane>

            <StackPanel Grid.Column="1" Margin="12,72">
                <TextBlock Text="File name:" Style="{StaticResource CaptionTextBlockStyle}"/>
                <TextBlock x:Name="FileNameTextBlock" Margin="0,0,0,12"/>

                <TextBlock Text="File path:" Style="{StaticResource CaptionTextBlockStyle}"/>
                <TextBlock x:Name="FilePathTextBlock" Margin="0,0,0,12"/>

                <TextBlock Text="Tree depth:" Style="{StaticResource CaptionTextBlockStyle}"/>
                <TextBlock x:Name="TreeDepthTextBlock" Margin="0,0,0,12"/>
            </StackPanel>
        </SplitView>
    </Grid>
</Page>
using System;
using System.Collections.Generic;
using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using muxc = Microsoft.UI.Xaml.Controls;

namespace TreeViewTest
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            InitializeTreeView();
        }

        private void InitializeTreeView()
        {
            // A TreeView can have more than 1 root node. The Pictures library
            // and the Music library will each be a root node in the tree.
            // Get Pictures library.
            StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
            muxc.TreeViewNode pictureNode = new muxc.TreeViewNode();
            pictureNode.Content = picturesFolder;
            pictureNode.IsExpanded = true;
            pictureNode.HasUnrealizedChildren = true;
            sampleTreeView.RootNodes.Add(pictureNode);
            FillTreeNode(pictureNode);

            // Get Music library.
            StorageFolder musicFolder = KnownFolders.MusicLibrary;
            muxc.TreeViewNode musicNode = new muxc.TreeViewNode();
            musicNode.Content = musicFolder;
            musicNode.IsExpanded = true;
            musicNode.HasUnrealizedChildren = true;
            sampleTreeView.RootNodes.Add(musicNode);
            FillTreeNode(musicNode);
        }

        private async void FillTreeNode(muxc.TreeViewNode node)
        {
            // Get the contents of the folder represented by the current tree node.
            // Add each item as a new child node of the node that's being expanded.

            // Only process the node if it's a folder and has unrealized children.
            StorageFolder folder = null;

            if (node.Content is StorageFolder && node.HasUnrealizedChildren == true)
            {
                folder = node.Content as StorageFolder;
            }
            else
            {
                // The node isn't a folder, or it's already been filled.
                return;
            }

            IReadOnlyList<IStorageItem> itemsList = await folder.GetItemsAsync();

            if (itemsList.Count == 0)
            {
                // The item is a folder, but it's empty. Leave HasUnrealizedChildren = true so
                // that the chevron appears, but don't try to process children that aren't there.
                return;
            }

            foreach (var item in itemsList)
            {
                var newNode = new muxc.TreeViewNode();
                newNode.Content = item;

                if (item is StorageFolder)
                {
                    // If the item is a folder, set HasUnrealizedChildren to true.
                    // This makes the collapsed chevron show up.
                    newNode.HasUnrealizedChildren = true;
                }
                else
                {
                    // Item is StorageFile. No processing needed for this scenario.
                }

                node.Children.Add(newNode);
            }

            // Children were just added to this node, so set HasUnrealizedChildren to false.
            node.HasUnrealizedChildren = false;
        }

        private void SampleTreeView_Expanding(muxc.TreeView sender, muxc.TreeViewExpandingEventArgs args)
        {
            if (args.Node.HasUnrealizedChildren)
            {
                FillTreeNode(args.Node);
            }
        }

        private void SampleTreeView_Collapsed(muxc.TreeView sender, muxc.TreeViewCollapsedEventArgs args)
        {
            args.Node.Children.Clear();
            args.Node.HasUnrealizedChildren = true;
        }

        private void SampleTreeView_ItemInvoked(muxc.TreeView sender, muxc.TreeViewItemInvokedEventArgs args)
        {
            var node = args.InvokedItem as muxc.TreeViewNode;

            if (node.Content is IStorageItem item)
            {
                FileNameTextBlock.Text = item.Name;
                FilePathTextBlock.Text = item.Path;
                TreeDepthTextBlock.Text = node.Depth.ToString();

                if (node.Content is StorageFolder)
                {
                    node.IsExpanded = !node.IsExpanded;
                }
            }
        }

        private void RefreshButton_Click(object sender, RoutedEventArgs e)
        {
            sampleTreeView.RootNodes.Clear();
            InitializeTreeView();
        }
    }

    public class ExplorerItemTemplateSelector : DataTemplateSelector
    {
        public DataTemplate DefaultTemplate { get; set; }
        public DataTemplate MusicItemTemplate { get; set; }
        public DataTemplate PictureItemTemplate { get; set; }
        public DataTemplate MusicFolderTemplate { get; set; }
        public DataTemplate PictureFolderTemplate { get; set; }

        protected override DataTemplate SelectTemplateCore(object item)
        {
            var node = (muxc.TreeViewNode)item;

            if (node.Content is StorageFolder)
            {
                var content = node.Content as StorageFolder;
                if (content.DisplayName.StartsWith("Pictures")) return PictureFolderTemplate;
                if (content.DisplayName.StartsWith("Music")) return MusicFolderTemplate;
            }
            else if (node.Content is StorageFile)
            {
                var content = node.Content as StorageFile;
                if (content.ContentType.StartsWith("image")) return PictureItemTemplate;
                if (content.ContentType.StartsWith("audio")) return MusicItemTemplate;

            }
            return DefaultTemplate;
        }
    }
}
Public NotInheritable Class MainPage
    Inherits Page

    Public Sub New()
        InitializeComponent()
        InitializeTreeView()
    End Sub

    Private Sub InitializeTreeView()
        ' A TreeView can have more than 1 root node. The Pictures library
        ' and the Music library will each be a root node in the tree.
        ' Get Pictures library.
        Dim picturesFolder As StorageFolder = KnownFolders.PicturesLibrary
        Dim pictureNode As New muxc.TreeViewNode With {
        .Content = picturesFolder,
        .IsExpanded = True,
        .HasUnrealizedChildren = True
    }
        sampleTreeView.RootNodes.Add(pictureNode)
        FillTreeNode(pictureNode)

        ' Get Music library.
        Dim musicFolder As StorageFolder = KnownFolders.MusicLibrary
        Dim musicNode As New muxc.TreeViewNode With {
        .Content = musicFolder,
        .IsExpanded = True,
        .HasUnrealizedChildren = True
    }
        sampleTreeView.RootNodes.Add(musicNode)
        FillTreeNode(musicNode)
    End Sub

    Private Async Sub FillTreeNode(node As muxc.TreeViewNode)
        ' Get the contents of the folder represented by the current tree node.
        ' Add each item as a new child node of the node that's being expanded.

        ' Only process the node if it's a folder and has unrealized children.
        Dim folder As StorageFolder = Nothing
        If TypeOf node.Content Is StorageFolder AndAlso node.HasUnrealizedChildren Then
            folder = TryCast(node.Content, StorageFolder)
        Else
            ' The node isn't a folder, or it's already been filled.
            Return
        End If

        Dim itemsList As IReadOnlyList(Of IStorageItem) = Await folder.GetItemsAsync()
        If itemsList.Count = 0 Then
            ' The item is a folder, but it's empty. Leave HasUnrealizedChildren = true so
            ' that the chevron appears, but don't try to process children that aren't there.
            Return
        End If

        For Each item In itemsList
            Dim newNode As New muxc.TreeViewNode With {
            .Content = item
        }
            If TypeOf item Is StorageFolder Then
                ' If the item is a folder, set HasUnrealizedChildren to True.
                ' This makes the collapsed chevron show up.
                newNode.HasUnrealizedChildren = True
            Else
                ' Item is StorageFile. No processing needed for this scenario.
            End If
            node.Children.Add(newNode)
        Next

        ' Children were just added to this node, so set HasUnrealizedChildren to False.
        node.HasUnrealizedChildren = False
    End Sub

    Private Sub SampleTreeView_Expanding(sender As muxc.TreeView, args As muxc.TreeViewExpandingEventArgs)
        If args.Node.HasUnrealizedChildren Then
            FillTreeNode(args.Node)
        End If
    End Sub

    Private Sub SampleTreeView_Collapsed(sender As muxc.TreeView, args As muxc.TreeViewCollapsedEventArgs)
        args.Node.Children.Clear()
        args.Node.HasUnrealizedChildren = True
    End Sub

    Private Sub SampleTreeView_ItemInvoked(sender As muxc.TreeView, args As muxc.TreeViewItemInvokedEventArgs)
        Dim node = TryCast(args.InvokedItem, muxc.TreeViewNode)
        Dim item = TryCast(node.Content, IStorageItem)
        If item IsNot Nothing Then
            FileNameTextBlock.Text = item.Name
            FilePathTextBlock.Text = item.Path
            TreeDepthTextBlock.Text = node.Depth.ToString()
            If TypeOf node.Content Is StorageFolder Then
                node.IsExpanded = Not node.IsExpanded
            End If
        End If
    End Sub

    Private Sub RefreshButton_Click(sender As Object, e As RoutedEventArgs)
        sampleTreeView.RootNodes.Clear()
        InitializeTreeView()
    End Sub

End Class

Public Class ExplorerItemTemplateSelector
    Inherits DataTemplateSelector

    Public Property DefaultTemplate As DataTemplate
    Public Property MusicItemTemplate As DataTemplate
    Public Property PictureItemTemplate As DataTemplate
    Public Property MusicFolderTemplate As DataTemplate
    Public Property PictureFolderTemplate As DataTemplate

    Protected Overrides Function SelectTemplateCore(ByVal item As Object) As DataTemplate
        Dim node = CType(item, muxc.TreeViewNode)

        If TypeOf node.Content Is StorageFolder Then
            Dim content = TryCast(node.Content, StorageFolder)
            If content.DisplayName.StartsWith("Pictures") Then Return PictureFolderTemplate
            If content.DisplayName.StartsWith("Music") Then Return MusicFolderTemplate
        ElseIf TypeOf node.Content Is StorageFile Then
            Dim content = TryCast(node.Content, StorageFile)
            If content.ContentType.StartsWith("image") Then Return PictureItemTemplate
            If content.ContentType.StartsWith("audio") Then Return MusicItemTemplate
        End If

        Return DefaultTemplate
    End Function
End Class

Trascinare la selezione di elementi tra visualizzazioni albero

L'esempio seguente illustra come creare due visualizzazioni albero in cui gli elementi di una visualizzazione possono essere trascinati e rilasciati nell'altra. Quando un elemento viene trascinato nell'altra visualizzazione albero, viene aggiunto alla fine dell'elenco. L'ordine degli elementi all'interno di una visualizzazione albero può comunque essere modificato. In questo esempio vengono prese in considerazione le visualizzazioni albero dell'account con un unico nodo radice.

<Page
    x:Class="TreeViewTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <TreeView x:Name="treeView1"
                  AllowDrop="True"
                  CanDragItems="True"
                  CanReorderItems="True"
                  DragOver="TreeView_DragOver"
                  Drop="TreeView_Drop"
                  DragItemsStarting="TreeView_DragItemsStarting"
                  DragItemsCompleted="TreeView_DragItemsCompleted"/>
        <TreeView x:Name="treeView2"
                  AllowDrop="True"
                  Grid.Column="1"
                  CanDragItems="True"
                  CanReorderItems="True"
                  DragOver="TreeView_DragOver"
                  Drop="TreeView_Drop"
                  DragItemsStarting="TreeView_DragItemsStarting"
                  DragItemsCompleted="TreeView_DragItemsCompleted"/>

    </Grid>

</Page>
using System;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace TreeViewTest
{
    public sealed partial class MainPage : Page
    {
        private TreeViewNode deletedItem;
        private TreeView sourceTreeView;

        public MainPage()
        {
            this.InitializeComponent();
            InitializeTreeView();
        }

        private void InitializeTreeView()
        {
            TreeViewNode parentNode1 = new TreeViewNode() { Content = "tv1" };
            TreeViewNode parentNode2 = new TreeViewNode() { Content = "tv2" };

            parentNode1.Children.Add(new TreeViewNode() { Content = "tv1FirstChild" });
            parentNode1.Children.Add(new TreeViewNode() { Content = "tv1SecondChild" });
            parentNode1.Children.Add(new TreeViewNode() { Content = "tv1ThirdChild" });
            parentNode1.Children.Add(new TreeViewNode() { Content = "tv1FourthChild" });
            parentNode1.IsExpanded = true;
            treeView1.RootNodes.Add(parentNode1);

            parentNode2.Children.Add(new TreeViewNode() { Content = "tv2FirstChild" });
            parentNode2.Children.Add(new TreeViewNode() { Content = "tv2SecondChild" });
            parentNode2.IsExpanded = true;
            treeView2.RootNodes.Add(parentNode2);
        }

        private void TreeView_DragOver(object sender, DragEventArgs e)
        {
            if (e.DataView.Contains(StandardDataFormats.Text))
            {
                e.AcceptedOperation = DataPackageOperation.Move;
            }
        }

        private async void TreeView_Drop(object sender, DragEventArgs e)
        {
            if (e.DataView.Contains(StandardDataFormats.Text))
            {
                string text = await e.DataView.GetTextAsync();
                TreeView destinationTreeView = sender as TreeView;

                if (destinationTreeView.RootNodes != null)
                {
                    TreeViewNode newNode = new TreeViewNode() { Content = text };
                    destinationTreeView.RootNodes[0].Children.Add(newNode);
                    deletedItem = newNode;
                }
            }
        }

        private void TreeView_DragItemsStarting(TreeView sender, TreeViewDragItemsStartingEventArgs args)
        {
            if (args.Items.Count == 1)
            {
                args.Data.RequestedOperation = DataPackageOperation.Move;
                sourceTreeView = sender;

                foreach (var item in args.Items)
                {
                    args.Data.SetText(item.ToString());
                }
            }
        }

        private void TreeView_DragItemsCompleted(TreeView sender, TreeViewDragItemsCompletedEventArgs args)
        {
            var children = sourceTreeView.RootNodes[0].Children;

            if (deletedItem != null)
            {
                for (int i = 0; i < children.Count; i++)
                {
                    if (children[i].Content.ToString() == deletedItem.Content.ToString())
                    {
                        children.RemoveAt(i);
                        break;
                    }
                }
            }

            sourceTreeView = null;
            deletedItem = null;
        }
    }
}