Udostępnij przez


Omówienie tworzenia szablonów 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 do modelu stylów i tworzenia szablonów WPF, obejmującym na przykład sposób użycia Style do ustawiania właściwości kontrolek, zobacz temat Styling and Templating (Stylowanie i Tworzenie Szablonów).

Ponadto ważne jest, aby zrozumieć Resources elementów, które zasadniczo umożliwiają, aby obiekty, takie jak Style i DataTemplate, były wielokrotnego użytku. Aby uzyskać więcej informacji na temat zasobów, zobacz sekcję 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), Priority (int) oraz właściwość typu TaskType, która jest elementem Enum 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:

Zrzut ekranu okna Wprowadzenie do przykładu szablonowania danych pokazujący ListBox

Chodzi o to, że bez żadnych konkretnych instrukcji, ListBox domyślnie wywołuje ToString, gdy próbujemy wyświetlić obiekty w kolekcji. W związku z tym, jeśli obiekt Task zastępuje metodę ToString, to ListBox wyświetla reprezentację ciągu każdego obiektu źródłowego w kolekcji bazowej.

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

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:

Zrzut ekranu przedstawiający okno przykładu wprowadzenia do szablonowania danych, pokazujący ListBox Moja lista zadań wyświetlający listę zadań.

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 właściwości ItemTemplate elementu ListBox na wartość DataTemplate. To, co określisz w DataTemplate, staje się wizualną strukturą twojego obiektu danych. Następujący DataTemplate jest dość prosty. Podajemy instrukcje, aby każdy element był wyświetlany jako trzy elementy TextBlock 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 mieć Path=TaskName, należy ustawić XPath na @TaskName (jeśli TaskName jest atrybutem twojego węzła XML).

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

Zrzut ekranu przedstawiający okno Wprowadzenie do tworzenia szablonów danych, pokazujące ListBox z listą zadań wyświetlanych jako elementy TextBlock.

Tworzenie 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 zasobem, można go teraz używać w innych kontrolkach, które mają właściwość przyjmującą typ DataTemplate. Jak pokazano powyżej, właściwością dla obiektów ItemsControl, takich jak ListBox, jest ItemTemplate. W przypadku obiektów ContentControl jest to właściwość ContentTemplate.

Właściwość DataType

Klasa DataTemplate ma właściwość DataType, która jest bardzo podobna do właściwości TargetType klasy Style. Zamiast określać x:Key dla DataTemplate w powyższym przykładzie, można zrobić następująco:

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

To DataTemplate zostanie automatycznie zastosowane 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 temu DataTemplate wartość x:Key, zastąpisz niejawną x:Key i DataTemplate nie zostanie zastosowana automatycznie.

W przypadku wiązania ContentControl z kolekcją obiektów Task, ContentControl nie używa 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 Twój ContentControl śledzi wybór typu ItemsControl, możesz ustawić właściwość Path powiązania na "ContentControl", żeby pokazać zainteresowanie bieżącym elementem. Aby zapoznać się z przykładem, zobacz Wiązanie z kolekcją i wyświetlanie informacji na podstawie wyboru. W przeciwnym razie trzeba jawnie określić DataTemplate poprzez ustawienie właściwości ContentTemplate.

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

Dodawanie więcej do 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 ListBox z tym zmodyfikowanym DataTemplate:

Zrzut ekranu okna Wprowadzenie do przykładowego szablonowania danych, pokazujący moją listę zadań na liście ListBox z zmodyfikowanym DataTemplate.

Możemy ustawić HorizontalContentAlignment na Stretch 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:

Zrzut ekranu przedstawiający okno Wprowadzenie do próbki szablonowania danych, pokazujący ListBox Listy moich zadań rozciągnięty tak, aby dopasować się do ekranu poziomo.

Użyj DataTriggers do zastosowania wartości właściwości

Bieżąca prezentacja nie informuje nas, czy Task jest to zadanie domowe, czy zadanie biurowe. Pamiętaj, że obiekt Task ma właściwość TaskType typu TaskType, która jest enumeracją 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 jasnoniebieskim obramowaniem.

Zrzut ekranu przedstawiający okno Wprowadzenie do przykładu tworzenia szablonów danych z listą zadań Moja lista zadańBox z obramowaniem zadań dla domu i biura wyróżnionymi kolorami.

W tym przykładzie DataTrigger używa Setter do ustawienia wartości właściwości. Klasy wyzwalacza mają właściwości EnterActions 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 właściwości BorderBrush z właściwością TaskType oraz użycie konwertera wartości w celu zwrócenia koloru na podstawie wartości TaskType. 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 za pomocą właściwości DataTemplate.Triggers. 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, których dotyczą dane Setters, nie są właściwościami elementów znajdujących się w bieżącym DataTemplate, może być bardziej odpowiednie ustawienie tych właściwości za pomocą klasy Style, która jest przeznaczona dla klasy ListBoxItem (jeśli formant, do którego się odwołujesz, jest ListBox). Na przykład, jeśli chcesz, aby Trigger animowało Opacity wartość elementu, gdy myszka wskazuje na dany element, zdefiniujesz wyzwalacze w stylu ListBoxItem. 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 stosowany jest do każdego wygenerowanego ListBoxItem (aby dowiedzieć się więcej o sposobie i miejscu jego zastosowania, zobacz ItemTemplate stronę). Twoja DataTemplate dotyczy wyłącznie prezentacji i wyglądu obiektów danych. W większości przypadków wszystkie inne aspekty prezentacji, takie jak wygląd elementu, gdy jest wybrany, lub sposób rozmieszczenia elementów przez ListBox, nie należą do definicji DataTemplate. Aby zapoznać się z przykładem, zobacz sekcję Stylowanie i Szablonowanie 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 kolekcje zawierające elementy 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 zechcieć nadać mu zupełnie inny wygląd, aby pełnił funkcję alertu dla Ciebie. 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 dostarczyć logikę wyboru, która DataTemplate ma być używana na podstawie wartości Priority obiektu danych, utwórz podklasę DataTemplateSelector i przesłoń metodę SelectTemplate. W poniższym przykładzie metoda SelectTemplate zapewnia logikę zwracania odpowiedniego szablonu w zależności od wartości właściwości Priority. Szablon, który należy zwrócić, znajduje się w zasobach elementu otaczającego 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 właściwości ItemTemplateSelector elementu ListBox. Metoda ListBox wywołuje metodę SelectTemplateTaskListDataTemplateSelector dla każdego elementu w kolekcji bazowej. Wywołanie przekazuje obiekt danych jako parametr elementu. Element DataTemplate zwracany przez metodę jest następnie stosowany do tego obiektu danych.

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

Teraz, gdy selektor szablonów jest na swoim miejscu, ListBox wyświetla się w następujący sposób:

Zrzut ekranu przedstawiający okno przykładowe Wprowadzenie do tworzenia szablonów danych, pokazujące ListBox z moją listą zadań, w którym zadania z priorytetem 1 są wyraźnie widoczne z czerwonym obramowaniem.

To kończy naszą dyskusję na temat tego przykładu. Pełny przykład można znaleźć w temacie Introduction to Data Templating Sample.

Stylowanie i tworzenie szablonów kontrolki ItemsControl

Mimo że ItemsControl nie jest jedynym typem kontrolki, którego można używać z DataTemplate, bardzo często łączy się 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 przykładzie ItemsControl jest powiązany z tą samą kolekcją Tasks, 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:

Przykładowy zrzut ekranu elementu ItemsControl

Należy pamiętać, że zamiast używać ItemTemplateelementu , możesz użyć elementu ItemTemplateSelector. Odwołaj się do poprzedniej sekcji, aby znaleźć przykład. Podobnie, zamiast używać elementu ItemContainerStyle, możesz zdecydować się na użycie 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 HierarchicalDataTemplate jest zaprojektowana do użycia z typami HeaderedItemsControl w celu wyświetlania takich danych. W poniższym przykładzie ListLeagueList jest to lista League obiektów. Każdy League obiekt ma Name element i kolekcję Division obiektów. Każda Division ma Name i kolekcję Team obiektów, a każdy obiekt Team ma 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.

Przykład zrzutu ekranu dla HierarchicalDataTemplate

Zobacz także