Przegląd Szablonowanie danych

Model tworzenia szablonów danych WPF zapewnia dużą elastyczność definiowania prezentacji danych. Kontrolki WPF mają wbudowaną funkcjonalność do obsługi dostosowywania prezentacji danych. W tym temacie najpierw pokazano, jak zdefiniować element DataTemplate , a następnie wprowadzić inne funkcje tworzenia szablonów danych, takie jak wybór szablonów na podstawie logiki niestandardowej i obsługa wyświetlania danych hierarchicznych.

Wymagania wstępne

Ten temat koncentruje się na funkcjach tworzenia szablonów danych i nie jest wprowadzeniem pojęć związanych z powiązaniem danych. Aby uzyskać informacje na temat podstawowych pojęć związanych z powiązaniem danych, zobacz Omówienie powiązania danych.

DataTemplate dotyczy prezentacji danych i jest jedną z wielu funkcji oferowanych przez model stylów I szablonów WPF. Aby zapoznać się z wprowadzeniem modelu stylów I tworzenia szablonów WPF, na przykład sposobu ustawiania Style właściwości kontrolek, zobacz temat Styling and Templating (Styling and Templating ).

Ponadto ważne jest, aby zrozumieć Resourceselement , które zasadniczo umożliwiają korzystanie z obiektów, takich jak Style i DataTemplate wielokrotnego użytku. Aby uzyskać więcej informacji na temat zasobów, zobacz Zasoby XAML.

Podstawy tworzenia szablonów danych

Aby zademonstrować, dlaczego DataTemplate jest to ważne, zapoznajmy się z przykładem powiązania danych. W tym przykładzie mamy obiekt ListBox powiązany z listą Task obiektów. Każdy Task obiekt ma TaskName (ciąg), Description ciąg (ciąg), ( Priority int) i właściwość typu TaskType, która jest Enum elementem z wartościami Home i 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>

Bez elementu DataTemplate

Bez elementu DataTemplatenasz ListBox obecnie wygląda następująco:

Screenshot of the Introduction to Data Templating Sample window showing the My Task List ListBox displaying the string representation SDKSample.Task for each source object.

Dzieje się tak, ListBox że bez żadnych konkretnych instrukcji domyślne wywołania ToString podczas próby wyświetlenia obiektów w kolekcji. W związku z tym, jeśli Task obiekt zastępuje metodę ToString , ListBox zostanie wyświetlona reprezentacja ciągu każdego obiektu źródłowego w kolekcji bazowej.

Jeśli na przykład Task klasa zastępuje metodę ToString w ten sposób, gdzie name jest polem dla TaskName właściwości:

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

Następnie element ListBox wygląda następująco:

Screenshot of the Introduction to Data Templating Sample window showing the My Task List ListBox displaying a list of tasks.

Jednak jest to ograniczenie i nieelastyczne. Ponadto w przypadku powiązania z danymi XML nie będzie można zastąpić ToStringelementu .

Definiowanie prostego elementu DataTemplate

Rozwiązaniem jest zdefiniowanie .DataTemplate Jednym ze sposobów, aby to zrobić, jest ustawienie ItemTemplate właściwości ListBoxDataTemplatena wartość . To, co określisz w obiekcie DataTemplate danych, staje się wizualną strukturą obiektu danych. Poniżej DataTemplate przedstawiono dość proste. Udostępniamy instrukcje, że każdy element jest wyświetlany jako trzy TextBlock elementy w elemencie StackPanel. Każdy TextBlock element jest powiązany z właściwością Task klasy.

<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>

Podstawowe dane przykładów w tym temacie to kolekcja obiektów CLR. Jeśli wiążesz się z danymi XML, podstawowe pojęcia są takie same, ale istnieje niewielka różnica składniowa. Na przykład zamiast , Path=TaskNamenależy ustawić wartość XPath@TaskName na (jeśli TaskName jest atrybutem węzła XML).

Teraz nasz ListBox wygląd wygląda następująco:

Screenshot of the Introduction to Data Templating Sample window showing the My Task List ListBox displaying the tasks as TextBlock elements.

Tworzenie elementu DataTemplate jako zasobu

W powyższym przykładzie zdefiniowaliśmy DataTemplate wbudowany wiersz. Bardziej typowe jest zdefiniowanie go w sekcji zasobów, dzięki czemu może być obiektem wielokrotnego użytku, jak w poniższym przykładzie:

<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>

Teraz możesz użyć myTaskTemplate jako zasobu, jak w poniższym przykładzie:

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

Ponieważ myTaskTemplate jest to zasób, można go teraz używać w innych kontrolkach, które mają właściwość, która przyjmuje DataTemplate typ. Jak pokazano powyżej, dla ItemsControl obiektów, takich jak ListBox, jest ItemTemplate to właściwość . W przypadku ContentControl obiektów jest ContentTemplate to właściwość .

Właściwość DataType

Klasa DataTemplate ma właściwość bardzo podobną DataTypeTargetType do właściwości Style klasy. W związku z tym zamiast określać x:Key element dla DataTemplate w powyższym przykładzie, można wykonać następujące czynności:

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

Spowoduje to DataTemplate automatyczne zastosowanie do wszystkich Task obiektów. Należy pamiętać, że w tym przypadku x:Key parametr jest ustawiany niejawnie. W związku z tym, jeśli przypiszesz tę wartość, zastąpisz niejawną DataTemplatex:Keyx:Key wartość i DataTemplate nie zostanie ona zastosowana automatycznie.

W przypadku powiązania ContentControl obiektu z kolekcją Task obiektów ContentControl obiekt nie jest używany automatycznie DataTemplate . Wynika to z faktu, że powiązanie elementu ContentControl wymaga dodatkowych informacji, aby określić, czy chcesz powiązać z całą kolekcją, czy poszczególnymi obiektami. Jeśli śledzisz ContentControl wybór ItemsControl typu, możesz ustawić Path właściwość ContentControl powiązania na "/", aby wskazać, że interesuje Cię bieżący element. Aby zapoznać się z przykładem, zobacz Wiązanie z kolekcją i Wyświetlanie informacji na podstawie zaznaczenia. W przeciwnym razie należy jawnie określić właściwość DataTemplate , ustawiając ContentTemplate właściwość .

Właściwość jest szczególnie przydatna DataType , gdy masz CompositeCollection różne typy obiektów danych. Przykład można znaleźć w temacie Implement a CompositeCollection (Implementowanie kolekcji CompositeCollection).

Dodawanie więcej do elementu DataTemplate

Obecnie dane są wyświetlane z niezbędnymi informacjami, ale zdecydowanie jest miejsce na poprawę. Ulepszmy prezentację, dodając element Border, a Gridi niektóre TextBlock elementy, które opisują wyświetlane dane.


<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>

Poniższy zrzut ekranu przedstawia element ListBox z tym zmodyfikowanym DataTemplateelementem :

Screenshot of the Introduction to Data Templating Sample window showing the My Task List ListBox with the modified DataTemplate.

Możemy ustawić HorizontalContentAlignmentStretch wartość na na , ListBox aby upewnić się, że szerokość elementów zajmuje całe miejsce:

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

Po ustawieniu HorizontalContentAlignment właściwości na Stretch, ListBox teraz wygląda następująco:

Screenshot of the Introduction to Data Templating Sample window showing the My Task List ListBox stretched to fit the screen horizontally.

Stosowanie wartości właściwości za pomocą elementów DataTriggers

Bieżąca prezentacja nie informuje nas, czy Task jest to zadanie domowe, czy zadanie biurowe. Pamiętaj, że Task obiekt ma TaskType właściwość typu TaskType, która jest wyliczeniem z wartościami Home i Work.

W poniższym przykładzie DataTrigger ustawia element BorderBrush o nazwie border na Yellow , jeśli TaskType właściwość ma wartość 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>

Nasza aplikacja wygląda teraz następująco. Zadania domowe pojawiają się z żółtym obramowaniem, a zadania biurowe pojawiają się z obramowaniem wodnym:

Screenshot of the Introduction to Data Templating Sample window showing the My Task List ListBox with the home and office task borders highlighted in color.

W tym przykładzie użyto DataTrigger elementu , Setter aby ustawić wartość właściwości. Klasy wyzwalacza mają EnterActions również właściwości i ExitActions , które umożliwiają uruchomienie zestawu akcji, takich jak animacje. Ponadto istnieje również MultiDataTrigger klasa, która umożliwia stosowanie zmian na podstawie wielu wartości właściwości powiązanych z danymi.

Alternatywnym sposobem osiągnięcia tego samego efektu jest powiązanie BorderBrush właściwości z właściwością TaskType i użycie konwertera wartości w celu zwrócenia koloru na TaskType podstawie wartości. Tworzenie powyższego efektu przy użyciu konwertera jest nieco bardziej wydajne pod względem wydajności. Ponadto tworzenie własnego konwertera zapewnia większą elastyczność, ponieważ dostarczasz własną logikę. Ostatecznie wybrana technika zależy od scenariusza i preferencji. Aby uzyskać informacje o sposobie pisania konwertera, zobacz IValueConverter.

Co należy do obiektu DataTemplate?

W poprzednim przykładzie umieściliśmy wyzwalacz w obiekcie DataTemplate przy użyciu DataTemplate.Triggers właściwości . Wyzwalacz Setter ustawia wartość właściwości elementu ( Border elementu), który znajduje się w obiekcie DataTemplate. Jeśli jednak właściwości, Setters których dotyczą dane, nie są właściwościami elementów znajdujących się w bieżącym DataTemplateelemencie , może być bardziej odpowiednie do ustawienia właściwości przy użyciu klasy Style , która jest przeznaczona dla ListBoxItem klasy (jeśli formant, który jest powiązaniem ListBox, jest ). Jeśli na przykład chcesz Trigger animować Opacity wartość elementu, gdy mysz wskazuje element, zdefiniujesz wyzwalacze w ListBoxItem stylu. Przykład można znaleźć w przykładzie Wprowadzenie do stylów i tworzenia szablonów.

Ogólnie rzecz biorąc, należy pamiętać, że DataTemplate element jest stosowany do każdego wygenerowanego ListBoxItem elementu (aby uzyskać więcej informacji na temat sposobu i miejsca rzeczywistego zastosowania, zobacz ItemTemplate stronę). Zajmujesz DataTemplate się tylko prezentacją i wyglądem obiektów danych. W większości przypadków wszystkie inne aspekty prezentacji, takie jak wygląd elementu w przypadku wybrania lub sposobu ListBox definiowania elementów, nie należą do definicji DataTemplateelementu . Aby zapoznać się z przykładem, zobacz sekcję Styling and Templating an ItemsControl (Styleing and Templating an ItemsControl ).

Wybieranie elementu DataTemplate na podstawie właściwości obiektu danych

W sekcji Właściwość DataType omówiliśmy, że można zdefiniować różne szablony danych dla różnych obiektów danych. Jest to szczególnie przydatne, gdy masz CompositeCollection różne typy lub kolekcje z elementami różnych typów. W sekcji Use DataTriggers to Apply Property Values (Stosowanie wartości właściwości) pokazano, że jeśli masz kolekcję obiektów danych tego samego typu, możesz utworzyć DataTemplate element , a następnie użyć wyzwalaczy, aby zastosować zmiany na podstawie wartości właściwości każdego obiektu danych. Jednak wyzwalacze umożliwiają stosowanie wartości właściwości lub animacji początkowej, ale nie zapewniają one elastyczności w celu odtworzenia struktury obiektów danych. Niektóre scenariusze mogą wymagać utworzenia innego DataTemplate obiektu danych, które są tego samego typu, ale mają różne właściwości.

Na przykład gdy Task obiekt ma Priority wartość 1, możesz chcieć nadać mu zupełnie inny wygląd, aby służyć jako alert dla siebie. W takim przypadku utworzysz obiekt DataTemplate dla wyświetlania obiektów o wysokim priorytcie Task . Dodajmy następujące elementy DataTemplate do sekcji zasobów:

<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>

W tym przykładzie użyto właściwości DataTemplate.Resources . Zasoby zdefiniowane w tej sekcji są współużytkowane przez elementy w obiekcie DataTemplate.

Aby podać logikę, która DataTemplate ma być używana na Priority podstawie wartości obiektu danych, utwórz podklasę DataTemplateSelector i przesłoń metodę SelectTemplate . W poniższym przykładzie SelectTemplate metoda zapewnia logikę, aby zwrócić odpowiedni szablon na podstawie wartości Priority właściwości. Szablon do zwrócenia znajduje się w zasobach elementu enveloping 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

Następnie możemy zadeklarować jako TaskListDataTemplateSelector zasób:

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

Aby użyć zasobu selektora szablonów, przypisz go do ItemTemplateSelector właściwości ListBox. Metoda ListBox wywołuje metodę SelectTemplateTaskListDataTemplateSelector dla każdego elementu w kolekcji bazowej. Wywołanie przekazuje obiekt danych jako parametr elementu. Metoda DataTemplate zwracana przez metodę jest następnie stosowana do tego obiektu danych.

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

Selektor szablonu jest teraz ListBox wyświetlany w następujący sposób:

Screenshot of Introduction to Data Templating Sample window showing the My Task List ListBox with the Priority 1 tasks prominently displayed with a red border.

To kończy naszą dyskusję na temat tego przykładu. Pełny przykład można znaleźć w temacie Introduction to Data Templating Sample (Wprowadzenie do przykładu tworzenia szablonów danych).

Stylowanie i tworzenie szablonów kontrolki ItemsControl

Mimo że ItemsControl nie jest to jedyny typ kontrolki, którego można użyć DataTemplate z, jest to bardzo typowy scenariusz powiązania elementu ItemsControl z kolekcją. W sekcji What Belongs in a DataTemplate (Co należy do elementu DataTemplate), omówiliśmy, że definicja elementu DataTemplate powinna dotyczyć tylko prezentacji danych. Aby dowiedzieć się, kiedy nie nadaje się do używania elementu DataTemplate , ważne jest, aby zrozumieć różne właściwości stylu i szablonu dostarczone przez element ItemsControl. Poniższy przykład został zaprojektowany w celu zilustrowania funkcji każdej z tych właściwości. W ItemsControl tym przykładzie element jest powiązany z tą samą Tasks kolekcją, co w poprzednim przykładzie. W celach demonstracyjnych style i szablony w tym przykładzie są zadeklarowane w tekście.

<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>

Poniżej przedstawiono zrzut ekranu przedstawiający przykład renderowania:

ItemsControl example screenshot

Należy pamiętać, że zamiast używać ItemTemplateelementu , możesz użyć elementu ItemTemplateSelector. Zapoznaj się z poprzednią sekcją, aby zapoznać się z przykładem. Podobnie zamiast używać ItemContainerStyleelementu , możesz użyć polecenia ItemContainerStyleSelector.

Dwie inne właściwości powiązane ze stylem elementu ItemsControl , które nie są tutaj wyświetlane, to GroupStyle i GroupStyleSelector.

Obsługa danych hierarchicznych

Do tej pory przyjrzeliśmy się tylko temu, jak powiązać i wyświetlić pojedynczą kolekcję. Czasami masz kolekcję zawierającą inne kolekcje. Klasa jest przeznaczona HierarchicalDataTemplate do użycia z typami HeaderedItemsControl do wyświetlania takich danych. W poniższym przykładzie ListLeagueList jest to lista League obiektów. Każdy League obiekt ma Name obiekt i kolekcję Division obiektów. Każda Division z nich ma Name obiekt i kolekcję Team obiektów, a każdy Team obiekt ma obiekt 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>

W przykładzie pokazano, że przy użyciu programu HierarchicalDataTemplatemożna łatwo wyświetlać dane listy zawierające inne listy. Poniżej przedstawiono zrzut ekranu przedstawiający przykład.

HierarchicalDataTemplate sample screenshot

Zobacz też