Condividi tramite


Panoramica della modellazione dati

Il modello di modellazione dei dati WPF offre una grande flessibilità per definire la presentazione dei dati. I controlli WPF dispongono di funzionalità predefinite per supportare la personalizzazione della presentazione dei dati. Questo argomento illustra innanzitutto come definire un DataTemplate oggetto e quindi introduce altre funzionalità di creazione di modelli di dati, ad esempio la selezione di modelli in base alla logica personalizzata e il supporto per la visualizzazione di dati gerarchici.

Prerequisiti

Questo argomento è incentrato sulle funzionalità di creazione di modelli di dati e non è un'introduzione dei concetti relativi al data binding. Per informazioni sui concetti di base sul data binding, vedere la Panoramica del data binding.

DataTemplate riguarda la presentazione dei dati ed è una delle numerose funzionalità fornite dal modello di applicazione di stili e modelli WPF. Per un'introduzione al modello di stilizzazione e templating WPF, ad esempio su come utilizzare un Style per impostare le proprietà sui controlli, vedere l'argomento Styling and Templating.

Inoltre, è importante comprendere Resources, che sono essenzialmente ciò che abilita oggetti come Style e DataTemplate per essere riutilizzabili. Per altre informazioni sulle risorse, vedi Risorse XAML.

Nozioni di base sulla creazione di modelli di dati

Per illustrare perché DataTemplate è importante, verrà illustrato un esempio di data binding. In questo esempio è presente un oggetto ListBox associato a un elenco di Task oggetti . Ogni Task oggetto ha una TaskName (stringa), una Description (stringa), un Priority (int) e una proprietà di tipo TaskType, che è un Enum oggetto con valori Home e Work.

<Window x:Class="SDKSample.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:SDKSample"
  Title="Introduction to Data Templating Sample">
  <Window.Resources>
    <local:Tasks x:Key="myTodoList"/>

</Window.Resources>
  <StackPanel>
    <TextBlock Name="blah" FontSize="20" Text="My Task List:"/>
    <ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}"/>
  </StackPanel>
</Window>

Senza DataTemplate

Senza un DataTemplate, il nostro ListBox attualmente ha questo aspetto:

Screenshot della finestra Introduction to Data Templating Sample che mostra il ListBox elenco delle mie attività, che visualizza la rappresentazione stringa SDKSample.Task per ogni oggetto di origine.

Ciò che accade è che, senza istruzioni specifiche, ListBox chiama ToString di default quando si tenta di visualizzare gli oggetti nella raccolta. Pertanto, se l'oggetto Task esegue l'override del metodo ToString, allora ListBox visualizza la rappresentazione in forma di stringa di ogni oggetto di origine nella collezione sottostante.

Ad esempio, se la classe Task esegue l'override del metodo ToString in questo modo, dove name è il campo per la proprietà TaskName:

public override string ToString()
{
    return name.ToString();
}
Public Overrides Function ToString() As String
    Return _name.ToString()
End Function

L'aspetto ListBox sarà quindi simile al seguente:

Screenshot della finestra Introduction to Data Templating Sample (Introduzione all'esempio di modelli di dati) che mostra la ListBox

Tuttavia, questo è limitante e inflessibile. Inoltre, se si esegue il binding ai dati XML, non sarà possibile eseguire l'override di ToString.

Definizione di un oggetto DataTemplate semplice

La soluzione consiste nel definire un oggetto DataTemplate. Un modo per eseguire questa operazione consiste nell'impostare la proprietà ItemTemplate di ListBox su un oggetto DataTemplate. Ciò che si specifica in DataTemplate diventa la struttura visiva dell'oggetto dati. Il seguente DataTemplate è piuttosto semplice. Stiamo fornendo istruzioni affinché ogni elemento appaia come tre TextBlock all'interno di un StackPanel. Ogni TextBlock elemento è associato a una proprietà della Task classe .

<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}">
   <ListBox.ItemTemplate>
     <DataTemplate>
       <StackPanel>
         <TextBlock Text="{Binding Path=TaskName}" />
         <TextBlock Text="{Binding Path=Description}"/>
         <TextBlock Text="{Binding Path=Priority}"/>
       </StackPanel>
     </DataTemplate>
   </ListBox.ItemTemplate>
 </ListBox>

I dati sottostanti per gli esempi in questo argomento sono una raccolta di oggetti CLR. Se si esegue il binding ai dati XML, i concetti fondamentali sono gli stessi, ma esiste una leggera differenza sintattica. Ad esempio, anziché avere Path=TaskName, dovresti impostare XPath su @TaskName (se TaskName è un attributo del tuo nodo XML).

Ora il nostro ListBox ha l'aspetto simile al seguente:

Screenshot della finestra Introduction to Data Templating Sample che mostra la casella Elenco attività personali che mostra le attività come elementi TextBlock.

Creazione di DataTemplate come risorsa

Nell'esempio precedente, abbiamo definito DataTemplate inline. È più comune definirlo nella sezione resources in modo che possa essere un oggetto riutilizzabile, come nell'esempio seguente:

<Window.Resources>
<DataTemplate x:Key="myTaskTemplate">
  <StackPanel>
    <TextBlock Text="{Binding Path=TaskName}" />
    <TextBlock Text="{Binding Path=Description}"/>
    <TextBlock Text="{Binding Path=Priority}"/>
  </StackPanel>
</DataTemplate>
</Window.Resources>

È ora possibile usare myTaskTemplate come risorsa, come nell'esempio seguente:

<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}"
         ItemTemplate="{StaticResource myTaskTemplate}"/>

Poiché myTaskTemplate è una risorsa, è ora possibile usarla in altri controlli con una proprietà che accetta un DataTemplate tipo. Come illustrato in precedenza, per gli oggetti ItemsControl, come ListBox, è la proprietà ItemTemplate. Per gli oggetti ContentControl, è la proprietà ContentTemplate.

Proprietà DataType

La DataTemplate classe ha una DataType proprietà molto simile alla TargetType proprietà della Style classe . Pertanto, invece di specificare un x:Key per nell'esempio DataTemplate precedente, è possibile eseguire le operazioni seguenti:

<DataTemplate DataType="{x:Type local:Task}">
  <StackPanel>
    <TextBlock Text="{Binding Path=TaskName}" />
    <TextBlock Text="{Binding Path=Description}"/>
    <TextBlock Text="{Binding Path=Priority}"/>
  </StackPanel>
</DataTemplate>

Questa operazione DataTemplate viene applicata automaticamente a tutti gli Task oggetti. Si noti che in questo caso l'oggetto x:Key viene impostato in modo implicito. Pertanto, se si assegna a questo DataTemplate un valore x:Key, si esegue l'override del valore implicito x:Key e il valore DataTemplate non verrà applicato automaticamente.

Se si associa un ContentControl a una raccolta di oggetti Task, il ContentControl non utilizza automaticamente il DataTemplate. Ciò è dovuto al fatto che l'associazione su un oggetto ContentControl necessita di ulteriori informazioni per distinguere se si desidera eseguire l'associazione a un'intera raccolta o a singoli oggetti. Se il tuo ContentControl sta tenendo traccia della selezione di un tipo di ItemsControl, puoi impostare la proprietà Path del binding ContentControl su "/" per indicare che ti interessa l'elemento corrente. Per un esempio, vedere Associare a una raccolta e visualizzare informazioni in base alla selezione. In caso contrario, è necessario specificare il DataTemplate esplicitamente impostando la proprietà ContentTemplate.

La DataType proprietà è particolarmente utile quando si dispone di diversi CompositeCollection tipi di oggetti dati. Per un esempio, vedere Implementare un oggetto CompositeCollection.

Aggiunta di ulteriori elementi al DataTemplate

Attualmente i dati appaiono con le informazioni necessarie, ma c'è sicuramente spazio per il miglioramento. Per migliorare la presentazione, aggiungere un Border, un Grid e alcuni TextBlock elementi che descrivono gli dati visualizzati.


<DataTemplate x:Key="myTaskTemplate">
  <Border Name="border" BorderBrush="Aqua" BorderThickness="1"
          Padding="5" Margin="5">
    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <TextBlock Grid.Row="0" Grid.Column="0" Text="Task Name:"/>
      <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=TaskName}" />
      <TextBlock Grid.Row="1" Grid.Column="0" Text="Description:"/>
      <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Description}"/>
      <TextBlock Grid.Row="2" Grid.Column="0" Text="Priority:"/>
      <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Priority}"/>
    </Grid>
  </Border>
</DataTemplate>

Lo screenshot seguente mostra il ListBox modificato con questo DataTemplate.

Screenshot della finestra Introduction to Data Templating Sample (Introduzione all'esempio di modelli di dati) che mostra il My Task List ListBox con il DataTemplate modificato.

È possibile impostare HorizontalContentAlignment su Stretch su ListBox per assicurarsi che la larghezza degli elementi occupi l'intero spazio:

<ListBox Width="400" Margin="10"
     ItemsSource="{Binding Source={StaticResource myTodoList}}"
     ItemTemplate="{StaticResource myTaskTemplate}" 
     HorizontalContentAlignment="Stretch"/>

Con la HorizontalContentAlignment proprietà impostata su Stretch, l'oggetto ListBox è ora simile al seguente:

Screenshot della finestra Introduction to Data Templating Sample (Introduzione all'esempio di modelli di dati) che mostra il controllo ListBox attività personale esteso per adattarsi orizzontalmente allo schermo.

Usare DataTriggers per applicare i valori delle proprietà

La presentazione corrente non indica se un oggetto Task è un'attività principale o un'attività di ufficio. Tenere presente che l'oggetto Task ha una TaskType proprietà di tipo TaskType, che è un'enumerazione con valori Home e Work.

Nell'esempio seguente, il DataTrigger imposta la BorderBrush dell'elemento denominato border su Yellow se la proprietà TaskType è TaskType.Home.

<DataTemplate x:Key="myTaskTemplate">
<DataTemplate.Triggers>
  <DataTrigger Binding="{Binding Path=TaskType}">
    <DataTrigger.Value>
      <local:TaskType>Home</local:TaskType>
    </DataTrigger.Value>
    <Setter TargetName="border" Property="BorderBrush" Value="Yellow"/>
  </DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>

L'applicazione avrà ora un aspetto simile al seguente. Le attività home vengono visualizzate con un bordo giallo e le attività di ufficio vengono visualizzate con un bordo aqua:

Screenshot della finestra Introduction to Data Templating Sample che mostra la My Task List ListBox con i bordi delle attività home e office evidenziati a colori.

In questo esempio DataTrigger usa Setter per impostare il valore di una proprietà. Le classi trigger hanno anche le EnterActions proprietà e ExitActions che consentono di avviare un set di azioni, ad esempio le animazioni. È inoltre disponibile una MultiDataTrigger classe che consente di applicare modifiche in base a più valori di proprietà associati a dati.

Un modo alternativo per ottenere lo stesso effetto consiste nell'associare la BorderBrush proprietà alla TaskType proprietà e usare un convertitore di valori per restituire il colore in base al TaskType valore. La creazione dell'effetto precedente tramite un convertitore è leggermente più efficiente in termini di prestazioni. Inoltre, la creazione di un convertitore personalizzato offre maggiore flessibilità perché si fornisce una logica personalizzata. In definitiva, la tecnica scelta dipende dallo scenario e dalle preferenze. Per informazioni su come scrivere un convertitore, vedere IValueConverter.

Che cosa è incluso in un DataTemplate?

Nell'esempio precedente il trigger è stato inserito all'interno di DataTemplate usando la DataTemplate.Triggers proprietà . L'oggetto Setter del trigger imposta il valore di una proprietà di un elemento (l'elemento Border ) che si trova all'interno di DataTemplate. Tuttavia, se le proprietà a cui il tuo Setters è interessato non sono proprietà di elementi che si trovano all'interno del DataTemplate corrente, potrebbe essere più opportuno impostare le proprietà usando un Style specifico per la classe ListBoxItem (se il controllo a cui si sta eseguendo l'associazione è un ListBox). Ad esempio, se vuoi che Trigger animi il Opacity valore dell'elemento quando un mouse punta a un elemento, definisci i attivatori all'interno di un ListBoxItem stile. Per un esempio, vedere Introduzione allo Styling e al Templating Sample.

In generale, tenere presente che il DataTemplate viene applicato a ognuno dei ListBoxItem generati (per ulteriori informazioni su come e dove viene effettivamente applicato, vedere la pagina ItemTemplate). L'oggetto DataTemplate si occupa solo della presentazione e dell'aspetto degli oggetti di dati. Nella maggior parte dei casi, tutti gli altri aspetti della presentazione, ad esempio l'aspetto di un elemento quando viene selezionato o come ListBox dispone gli elementi, non appartengono alla definizione di un oggetto DataTemplate. Per un esempio, vedere la sezione Stile e modelli di ItemsControl.

Scelta di un oggetto DataTemplate in base alle proprietà dell'oggetto dati

Nella sezione Proprietà DataType è stato illustrato come definire modelli di dati diversi per oggetti dati diversi. Ciò è particolarmente utile quando si dispone di tipi diversi CompositeCollection o di raccolte con elementi di tipi diversi. Nella sezione Use DataTriggers to Apply Property Values (Usa DataTriggers per applicare i valori delle proprietà ) è stato mostrato che se si dispone di una raccolta dello stesso tipo di oggetti dati è possibile creare un DataTemplate oggetto e quindi usare trigger per applicare le modifiche in base ai valori delle proprietà di ogni oggetto dati. Tuttavia, i trigger consentono di applicare valori di proprietà o animazioni di avvio, ma non offrono la flessibilità necessaria per ricostruire la struttura degli oggetti dati. Alcuni scenari possono richiedere la creazione di un oggetto diverso DataTemplate per gli oggetti dati dello stesso tipo, ma con proprietà diverse.

Ad esempio, quando un Task oggetto ha un Priority valore di 1, può essere necessario assegnargli un aspetto completamente diverso per fungere da avviso per se stessi. In tal caso, si crea un oggetto DataTemplate per la visualizzazione degli oggetti con priorità Task alta. Aggiungere quanto segue DataTemplate alla sezione resources:

<DataTemplate x:Key="importantTaskTemplate">
  <DataTemplate.Resources>
    <Style TargetType="TextBlock">
      <Setter Property="FontSize" Value="20"/>
    </Style>
  </DataTemplate.Resources>
  <Border Name="border" BorderBrush="Red" BorderThickness="1"
          Padding="5" Margin="5">
    <DockPanel HorizontalAlignment="Center">
      <TextBlock Text="{Binding Path=Description}" />
      <TextBlock>!</TextBlock>
    </DockPanel>
  </Border>
</DataTemplate>

In questo esempio viene utilizzata la proprietà DataTemplate.Resources . Le risorse definite in tale sezione vengono condivise dagli elementi all'interno di DataTemplate.

Per fornire la logica per scegliere quale DataTemplate utilizzare in base al Priority valore dell'oggetto dati, creare una sottoclasse di DataTemplateSelector ed eseguire l'override del SelectTemplate metodo. Nell'esempio seguente il SelectTemplate metodo fornisce la logica per restituire il modello appropriato in base al valore della Priority proprietà . Il modello da restituire si trova nelle risorse dell'elemento avvolgente Window .

using System.Windows;
using System.Windows.Controls;

namespace SDKSample
{
    public class TaskListDataTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate
            SelectTemplate(object item, DependencyObject container)
        {
            FrameworkElement element = container as FrameworkElement;

            if (element != null && item != null && item is Task)
            {
                Task taskitem = item as Task;

                if (taskitem.Priority == 1)
                    return
                        element.FindResource("importantTaskTemplate") as DataTemplate;
                else
                    return
                        element.FindResource("myTaskTemplate") as DataTemplate;
            }

            return null;
        }
    }
}

Namespace SDKSample
    Public Class TaskListDataTemplateSelector
        Inherits DataTemplateSelector
        Public Overrides Function SelectTemplate(ByVal item As Object, ByVal container As DependencyObject) As DataTemplate

            Dim element As FrameworkElement
            element = TryCast(container, FrameworkElement)

            If element IsNot Nothing AndAlso item IsNot Nothing AndAlso TypeOf item Is Task Then

                Dim taskitem As Task = TryCast(item, Task)

                If taskitem.Priority = 1 Then
                    Return TryCast(element.FindResource("importantTaskTemplate"), DataTemplate)
                Else
                    Return TryCast(element.FindResource("myTaskTemplate"), DataTemplate)
                End If
            End If

            Return Nothing
        End Function
    End Class
End Namespace

Possiamo quindi dichiarare TaskListDataTemplateSelector come una risorsa.

<Window.Resources>
<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>
</Window.Resources>

Per usare la risorsa del selettore di modelli, assegnarla alla proprietà ItemTemplateSelector di ListBox. Il ListBox chiama il metodo SelectTemplate del TaskListDataTemplateSelector per ciascuno degli elementi nella raccolta sottostante. La chiamata passa l'oggetto dati come parametro dell'elemento. L'oggetto DataTemplate restituito dal metodo viene quindi applicato all'oggetto dati.

<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}"
         ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
         HorizontalContentAlignment="Stretch"/>

Con il selettore di modello sul posto, il ListBox ora appare come segue:

Screenshot della finestra Introduction to Data Templating Sample (Introduzione all'esempio di modelli di dati) che mostra la casella Elenco attività personali con le attività con priorità 1 visualizzate in modo evidente con un bordo rosso.

Questo conclude la discussione su questo esempio. Per l'esempio completo, vedere Introduction to Data Templating Sample (Introduzione all'esempio di modelli di dati).

Applicazione di stili e modellazione a ItemsControl

Anche se ItemsControl non è l'unico tipo di controllo con cui è possibile usare un DataTemplate, si tratta di uno scenario molto comune per collegare un ItemsControl a una raccolta. Nella sezione What Belongs in a DataTemplate è stato illustrato che la definizione del tuo DataTemplate dovrebbe occuparsi solo della presentazione dei dati. Per sapere quando non è adatto per usare un DataTemplate è importante comprendere le diverse proprietà di stile e modello fornite da ItemsControl. L'esempio seguente è progettato per illustrare la funzione di ognuna di queste proprietà. Il ItemsControl in questo esempio è vincolato alla stessa raccolta Tasks dell'esempio precedente. A scopo dimostrativo, gli stili e i modelli in questo esempio sono tutti dichiarati inline.

<ItemsControl Margin="10"
              ItemsSource="{Binding Source={StaticResource myTodoList}}">
  <!--The ItemsControl has no default visual appearance.
      Use the Template property to specify a ControlTemplate to define
      the appearance of an ItemsControl. The ItemsPresenter uses the specified
      ItemsPanelTemplate (see below) to layout the items. If an
      ItemsPanelTemplate is not specified, the default is used. (For ItemsControl,
      the default is an ItemsPanelTemplate that specifies a StackPanel.-->
  <ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
      <Border BorderBrush="Aqua" BorderThickness="1" CornerRadius="15">
        <ItemsPresenter/>
      </Border>
    </ControlTemplate>
  </ItemsControl.Template>
  <!--Use the ItemsPanel property to specify an ItemsPanelTemplate
      that defines the panel that is used to hold the generated items.
      In other words, use this property if you want to affect
      how the items are laid out.-->
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <WrapPanel />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <!--Use the ItemTemplate to set a DataTemplate to define
      the visualization of the data objects. This DataTemplate
      specifies that each data object appears with the Proriity
      and TaskName on top of a silver ellipse.-->
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <DataTemplate.Resources>
        <Style TargetType="TextBlock">
          <Setter Property="FontSize" Value="18"/>
          <Setter Property="HorizontalAlignment" Value="Center"/>
        </Style>
      </DataTemplate.Resources>
      <Grid>
        <Ellipse Fill="Silver"/>
        <StackPanel>
          <TextBlock Margin="3,3,3,0"
                     Text="{Binding Path=Priority}"/>
          <TextBlock Margin="3,0,3,7"
                     Text="{Binding Path=TaskName}"/>
        </StackPanel>
      </Grid>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
  <!--Use the ItemContainerStyle property to specify the appearance
      of the element that contains the data. This ItemContainerStyle
      gives each item container a margin and a width. There is also
      a trigger that sets a tooltip that shows the description of
      the data object when the mouse hovers over the item container.-->
  <ItemsControl.ItemContainerStyle>
    <Style>
      <Setter Property="Control.Width" Value="100"/>
      <Setter Property="Control.Margin" Value="5"/>
      <Style.Triggers>
        <Trigger Property="Control.IsMouseOver" Value="True">
          <Setter Property="Control.ToolTip"
                  Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                          Path=Content.Description}"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </ItemsControl.ItemContainerStyle>
</ItemsControl>

Di seguito è riportato uno screenshot dell'esempio quando viene eseguito il rendering:

Screenshot dell'esempio itemsControl

Si noti che invece di usare ItemTemplate, è possibile usare ItemTemplateSelector. Per un esempio, vedere la sezione precedente. Analogamente, invece di usare il ItemContainerStyle, è possibile usare il ItemContainerStyleSelector.

Altre due proprietà correlate allo stile di ItemsControl che non sono illustrate di seguito sono GroupStyle e GroupStyleSelector.

Supporto per i dati gerarchici

Finora abbiamo esaminato solo come associare e visualizzare una singola raccolta. In alcuni casi si dispone di una raccolta che contiene altre raccolte. La HierarchicalDataTemplate classe è progettata per essere usata con HeaderedItemsControl i tipi per visualizzare tali dati. Nell'esempio seguente è ListLeagueList riportato un elenco di League oggetti . Ogni League oggetto ha un Name e una collezione di Division oggetti. Ogni Division ha un Name e una raccolta di oggetti Team, e ogni oggetto Team ha un Name.

<Window x:Class="SDKSample.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="HierarchicalDataTemplate Sample"
  xmlns:src="clr-namespace:SDKSample">
  <DockPanel>
    <DockPanel.Resources>
      <src:ListLeagueList x:Key="MyList"/>

      <HierarchicalDataTemplate DataType    = "{x:Type src:League}"
                                ItemsSource = "{Binding Path=Divisions}">
        <TextBlock Text="{Binding Path=Name}"/>
      </HierarchicalDataTemplate>

      <HierarchicalDataTemplate DataType    = "{x:Type src:Division}"
                                ItemsSource = "{Binding Path=Teams}">
        <TextBlock Text="{Binding Path=Name}"/>
      </HierarchicalDataTemplate>

      <DataTemplate DataType="{x:Type src:Team}">
        <TextBlock Text="{Binding Path=Name}"/>
      </DataTemplate>
    </DockPanel.Resources>

    <Menu Name="menu1" DockPanel.Dock="Top" Margin="10,10,10,10">
        <MenuItem Header="My Soccer Leagues"
                  ItemsSource="{Binding Source={StaticResource MyList}}" />
    </Menu>

    <TreeView>
      <TreeViewItem ItemsSource="{Binding Source={StaticResource MyList}}" Header="My Soccer Leagues" />
    </TreeView>

  </DockPanel>
</Window>

L'esempio mostra che con l'uso di è possibile visualizzare facilmente i dati dell'elenco HierarchicalDataTemplateche contengono altri elenchi. Lo screenshot seguente mostra l'esempio.

Screenshot di esempio di HierarchicalDataTemplate

Vedere anche