Общие сведения о шаблонах данныхData Templating Overview

Модель шаблонов данных WPF предоставляет большую гибкость при определении представления данных.The WPF data templating model provides you with great flexibility to define the presentation of your data. Элементы управления WPF имеют встроенные функции для поддержки настройки представления данных.WPF controls have built-in functionality to support the customization of data presentation. В этом разделе сначала показано, как определить DataTemplate , а затем появились другие возможности создания шаблонов данных, такие как выбор шаблонов на основе пользовательской логики и поддержка отображения иерархических данных.This topic first demonstrates how to define a DataTemplate and then introduces other data templating features, such as the selection of templates based on custom logic and the support for the display of hierarchical data.

Предварительные требованияPrerequisites

В этом разделе рассматриваются функции шаблонов данных. Здесь отсутствуют общие сведения о понятиях привязки данных.This topic focuses on data templating features and is not an introduction of data binding concepts. Сведения о базовых концепциях привязки данных содержатся в разделе Обзор привязки данных.For information about basic data binding concepts, see the Data Binding Overview.

DataTemplateявляется представлением данных и является одной из многих функций, предоставляемых моделью стилизации и шаблонов WPF.DataTemplate is about the presentation of data and is one of the many features provided by the WPF styling and templating model. Общие сведения о модели стилизации и шаблонов WPF, например о том, как использовать Style для задания свойств элементов управления, см. в разделе Стилизация и шаблоны .For an introduction of the WPF styling and templating model, such as how to use a Style to set properties on controls, see the Styling and Templating topic.

Кроме того, важно понимать Resources, что по сути позволяет использовать объекты, такие как Style и, DataTemplate для многократного использования.In addition, it is important to understand Resources, which are essentially what enable objects such as Style and DataTemplate to be reusable. Дополнительные сведения о ресурсах см. в разделе Ресурсы XAML.For more information on resources, see XAML Resources.

Основные сведения о шаблонах данныхData Templating Basics

Чтобы продемонстрировать, DataTemplate почему это важно, давайте рассмотрим пример привязки данных.To demonstrate why DataTemplate is important, let's walk through a data binding example. В этом примере есть ListBox привязка, привязанная к Task списку объектов.In this example, we have a ListBox that is bound to a list of Task objects. Каждому Task объекту соответствует TaskName (строка), Description (строка), Priority (int) и свойство типа TaskType, которое является Enum со значениями Home и Work.Each Task object has a TaskName (string), a Description (string), a Priority (int), and a property of type TaskType, which is an Enum with values Home and 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>

Без шаблона данных DataTemplateWithout a DataTemplate

В настоящее время наш ListBox код выглядит следующим образом: DataTemplateWithout a DataTemplate, our ListBox currently looks like this:

Снимок экрана образца шаблонов данныхData templating sample screenshot

Что происходит без каких-либо специальных инструкций, ListBox по умолчанию вызывается ToString при попытке отобразить объекты в коллекции.What's happening is that without any specific instructions, the ListBox by default calls ToString when trying to display the objects in the collection. Таким образом, если Task объект ToString переопределяет метод, то ListBox отображает строковое представление каждого исходного объекта в базовой коллекции.Therefore, if the Task object overrides the ToString method, then the ListBox displays the string representation of each source object in the underlying collection.

Например, если класс Task переопределяет метод ToString таким образом, что name — поле для TaskName свойства:For example, if the Task class overrides the ToString method this way, where name is the field for the TaskName property:

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

Затем он ListBox выглядит следующим образом:Then the ListBox looks like the following:

Снимок экрана образца шаблонов данныхData templating sample screenshot

Тем не менее это характеризуется ограниченностью и негибкостью.However, that is limiting and inflexible. Кроме того, если выполняется привязка к даннымXMLXML, невозможно переопределить ToString.Also, if you are binding to XMLXML data, you wouldn't be able to override ToString.

Определение простого шаблона DataTemplateDefining a Simple DataTemplate

Решение заключается в определении DataTemplate.The solution is to define a DataTemplate. Одним из способов сделать это является присвоение ItemTemplate свойству значения. ListBox DataTemplateOne way to do that is to set the ItemTemplate property of the ListBox to a DataTemplate. То, что вы указываете в DataTemplate , станет визуальной структурой объекта данных.What you specify in your DataTemplate becomes the visual structure of your data object. Следующий пример DataTemplate довольно прост.The following DataTemplate is fairly simple. Мы предоставляем инструкции, которые каждый элемент отображается как три TextBlock элемента StackPanelв.We are giving instructions that each item appears as three TextBlock elements within a StackPanel. Каждый TextBlock элемент привязан к свойству Task класса.Each TextBlock element is bound to a property of the Task class.

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

Базовые данные для примеров в этом разделе представляют собой коллекцию объектов CLR.The underlying data for the examples in this topic is a collection of CLR objects. Если выполнить привязку к данным XMLXML, основные понятия схожи, но есть незначительные синтаксические различия.If you are binding to XMLXML data, the fundamental concepts are the same, but there is a slight syntactic difference. Path=TaskNameНапример, вместо параметра необходимо @TaskName задать значение XPath (если TaskName является атрибутом вашего XMLXML узла).For example, instead of having Path=TaskName, you would set XPath to @TaskName (if TaskName is an attribute of your XMLXML node).

Теперь наш ListBox вид выглядит следующим образом:Now our ListBox looks like the following:

Снимок экрана образца шаблонов данныхData templating sample screenshot

Создание шаблона DataTemplate как ресурсаCreating the DataTemplate as a Resource

В приведенном выше примере мы определили DataTemplate встроенное.In the above example, we defined the DataTemplate inline. Обычно его определяют в разделе ресурсов, чтобы его можно было повторно использовать, как в следующем примере:It is more common to define it in the resources section so it can be a reusable object, as in the following example:

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

Теперь вы можете использовать myTaskTemplate в качестве ресурса, как показано в следующем примере:Now you can use myTaskTemplate as a resource, as in the following example:

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

Так myTaskTemplate как является ресурсом, теперь его можно использовать в других элементах управления, имеющих свойство, DataTemplate принимающее тип.Because myTaskTemplate is a resource, you can now use it on other controls that have a property that takes a DataTemplate type. Как показано выше, для ItemsControl объектов, таких ListBoxкак, ItemTemplate это свойство.As shown above, for ItemsControl objects, such as the ListBox, it is the ItemTemplate property. Для ContentControl объектовContentTemplate это свойство.For ContentControl objects, it is the ContentTemplate property.

Свойство DataTypeThe DataType Property

Класс имеет свойство, которое очень похоже Style на TargetType свойство класса. DataType DataTemplateThe DataTemplate class has a DataType property that is very similar to the TargetType property of the Style class. Таким образом, вместо указания x:Key DataTemplate для для в приведенном выше примере можно выполнить следующие действия.Therefore, instead of specifying an x:Key for the DataTemplate in the above example, you can do the following:

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

Он DataTemplate применяется автоматически ко всем Task объектам.This DataTemplate gets applied automatically to all Task objects. Обратите внимание, что в этом случае x:Key устанавливается неявно.Note that in this case the x:Key is set implicitly. Таким образом, если вы назначаете x:Key это DataTemplate значение, вы DataTemplate переопределяете неявное x:Key и не будет применяться автоматически.Therefore, if you assign this DataTemplate an x:Key value, you are overriding the implicit x:Key and the DataTemplate would not be applied automatically.

При привязке ContentControl к Task коллекции объектов ContentControl объект не использует приведенный выше DataTemplate объект автоматически.If you are binding a ContentControl to a collection of Task objects, the ContentControl does not use the above DataTemplate automatically. Это обусловлено тем, что для ContentControl привязки к требуется больше сведений, чтобы определить, нужно ли выполнять привязку к целой коллекции или к отдельным объектам.This is because the binding on a ContentControl needs more information to distinguish whether you want to bind to an entire collection or the individual objects. Path ContentControl /Если вы отслеживаете выбор ItemsControl типа, можно присвоить свойству привязки значение "", чтобы указать, что вы заинтересованы в текущем элементе. ContentControlIf your ContentControl is tracking the selection of an ItemsControl type, you can set the Path property of the ContentControl binding to "/" to indicate that you are interested in the current item. Для примера см. Выполнение привязки к коллекции и вывод сведений в зависимости от выделенного элемента.For an example, see Bind to a Collection and Display Information Based on Selection. В противном случае необходимо DataTemplate явно ContentTemplate указать значение свойства.Otherwise, you need to specify the DataTemplate explicitly by setting the ContentTemplate property.

Свойство особенно полезно при CompositeCollection наличии различных типов объектов данных. DataTypeThe DataType property is particularly useful when you have a CompositeCollection of different types of data objects. Пример см. в разделе Реализация CompositeCollection.For an example, see Implement a CompositeCollection.

Добавление дополнительных данных в DataTemplateAdding More to the DataTemplate

В настоящее время данные содержат необходимую информацию, но определенно это можно улучшить.Currently the data appears with the necessary information, but there's definitely room for improvement. Давайте улучшаем презентацию, добавляя Border Grid, и некоторые TextBlock элементы, описывающие отображаемые данные.Let's improve on the presentation by adding a Border, a Grid, and some TextBlock elements that describe the data that is being displayed.


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

На следующем снимке экрана ListBox показано, что DataTemplateизменилось:The following screenshot shows the ListBox with this modified DataTemplate:

Снимок экрана образца шаблонов данныхData templating sample screenshot

Мы можем задать HorizontalContentAlignment для Stretch значение ON ListBox , чтобы убедиться, что ширина элементов занимает все пространство:We can set HorizontalContentAlignment to Stretch on the ListBox to make sure the width of the items takes up the entire space:

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

Если свойство имеет Stretchзначение, теперь он ListBox выглядит следующим образом: HorizontalContentAlignmentWith the HorizontalContentAlignment property set to Stretch, the ListBox now looks like this:

Снимок экрана образца шаблонов данныхData templating sample screenshot

Использование триггеров данных для применения значений свойствUse DataTriggers to Apply Property Values

В настоящей презентации не говорится о том, является ли Task домашней задачей или офисной.The current presentation does not tell us whether a Task is a home task or an office task. Помните, что объект Task имеет свойство TaskType типа TaskType, который является перечислением со значениями Home и Work.Remember that the Task object has a TaskType property of type TaskType, which is an enumeration with values Home and Work.

В следующем DataTrigger примере параметр BorderBrush задает для border Yellow элементасTaskType.Homeименем значение, если свойствоимеетзначение.TaskTypeIn the following example, the DataTrigger sets the BorderBrush of the element named border to Yellow if the TaskType property is 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>

Наше приложение теперь выглядит следующим образом.Our application now looks like the following. Домашние задачи отображаются с желтой границей, а офисные — с синей границей:Home tasks appear with a yellow border and office tasks appear with an aqua border:

Снимок экрана образца шаблонов данныхData templating sample screenshot

В этом примере DataTrigger Setter компонент использует для задания значения свойства.In this example the DataTrigger uses a Setter to set a property value. Классы триггеров также имеют EnterActions свойства и ExitActions , позволяющие запускать набор действий, таких как анимация.The trigger classes also have the EnterActions and ExitActions properties that allow you to start a set of actions such as animations. Кроме того, существует также MultiDataTrigger класс, позволяющий применять изменения на основе нескольких значений свойств, привязанных к данным.In addition, there is also a MultiDataTrigger class that allows you to apply changes based on multiple data-bound property values.

Другой способ добиться того же результата — привязать BorderBrush свойство TaskType к свойству и использовать преобразователь значений для возврата цвета на основе TaskType значения.An alternative way to achieve the same effect is to bind the BorderBrush property to the TaskType property and use a value converter to return the color based on the TaskType value. Создание вышеупомянутого эффекта с помощью преобразователя является немного более эффективным с точки зрения производительности.Creating the above effect using a converter is slightly more efficient in terms of performance. Кроме того, создание собственных преобразователей обеспечивает большую гибкость, так как вы предоставляете свою собственную логику.Additionally, creating your own converter gives you more flexibility because you are supplying your own logic. В конечном счете выбор техники зависит от сценария и предпочтений.Ultimately, which technique you choose depends on your scenario and your preference. Дополнительные сведения о создании преобразователя см. в разделе IValueConverter.For information about how to write a converter, see IValueConverter.

Что входит в DataTemplate?What Belongs in a DataTemplate?

В предыдущем примере мы поместили триггер DataTemplate в с DataTemplateпомощью.TriggersIn the previous example, we placed the trigger within the DataTemplate using the DataTemplate.Triggers .property. Триггер задает значение свойства элемента Border (элемента DataTemplate), который находится в. SetterThe Setter of the trigger sets the value of a property of an element (the Border element) that is within the DataTemplate. Однако если свойства Setters , с которыми связаны вопросы, не являются свойствами элементов, находящихся в текущем DataTemplateобъекте, то может оказаться более подходящим Style задание свойств с помощью ListBoxItem класса, который предназначен для этого (если элемент управления, к ListBoxкоторому выполняется привязка, —).However, if the properties that your Setters are concerned with are not properties of elements that are within the current DataTemplate, it may be more suitable to set the properties using a Style that is for the ListBoxItem class (if the control you are binding is a ListBox). Например, если нужно Trigger Opacity анимировать значение элемента при наведении указателя мыши на элемент, ListBoxItem можно определить триггеры в стиле.For example, if you want your Trigger to animate the Opacity value of the item when a mouse points to an item, you define triggers within a ListBoxItem style. Пример см. в разделе Вводная часть примера стилизации и использования шаблонов.For an example, see the Introduction to Styling and Templating Sample.

В общем случае помните, что DataTemplate применяется к каждому из созданных ListBoxItem (Дополнительные сведения о том, как и где она применяется, см. на ItemTemplate странице).In general, keep in mind that the DataTemplate is being applied to each of the generated ListBoxItem (for more information about how and where it is actually applied, see the ItemTemplate page.). Для DataTemplate вас важна только презентация и внешний вид объектов данных.Your DataTemplate is concerned with only the presentation and appearance of the data objects. В большинстве случаев все остальные аспекты презентации, например сведения о том, как выглядит элемент, когда он выбран, или о том ListBox , как размещает элементы, не принадлежат в определении. DataTemplateIn most cases, all other aspects of presentation, such as what an item looks like when it is selected or how the ListBox lays out the items, do not belong in the definition of a DataTemplate. Пример см. в разделе Стилизация и использование шаблонов для ItemsControl.For an example, see the Styling and Templating an ItemsControl section.

Выбор DataTemplate на основе свойств объекта данныхChoosing a DataTemplate Based on Properties of the Data Object

В разделе Свойство DataType мы говорили о том, что можно определить различные шаблоны данных для различных объектов данных.In The DataType Property section, we discussed that you can define different data templates for different data objects. Это особенно полезно при наличии CompositeCollection различных типов или коллекций с элементами различных типов.That is especially useful when you have a CompositeCollection of different types or collections with items of different types. В разделе Использование триггеров данных для применения значений свойств мы показали, что при наличии коллекции одного DataTemplate и того же типа объектов Data можно создать, а затем использовать триггеры для применения изменений на основе значений свойств каждого объекта данных.In the Use DataTriggers to Apply Property Values section, we have shown that if you have a collection of the same type of data objects you can create a DataTemplate and then use triggers to apply changes based on the property values of each data object. Тем не менее, хотя триггеры позволяют применить значения свойств или запустить анимацию, они не предоставляют гибкость, достаточную для реконструкции структуры объектов данных.However, triggers allow you to apply property values or start animations but they don't give you the flexibility to reconstruct the structure of your data objects. Некоторые сценарии могут потребовать создания различных DataTemplate объектов данных одного типа, но имеют разные свойства.Some scenarios may require you to create a different DataTemplate for data objects that are of the same type but have different properties.

Например, если объект Task имеет значение Priority свойства 1, вы можете задать совершенно другой вид для него, чтобы сделать его сигналом оповещения.For example, when a Task object has a Priority value of 1, you may want to give it a completely different look to serve as an alert for yourself. В этом случае для просмотра объектов с DataTemplate высоким приоритетом Task создается объект.In that case, you create a DataTemplate for the display of the high-priority Task objects. Добавим следующий DataTemplate элемент в раздел Resources:Let's add the following DataTemplate to the resources section:

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

Обратите внимание, что DataTemplateв этом примере используется.ResourcesNotice this example uses the DataTemplate.Resources .property. Ресурсы, определенные в этом разделе, совместно используются элементами DataTemplateв.Resources defined in that section are shared by the elements within the DataTemplate.

Чтобы указать логику DataTemplate , используемую в зависимости Priority от значения объекта данных, создайте SelectTemplate подкласс класса DataTemplateSelector и переопределите метод.To supply logic to choose which DataTemplate to use based on the Priority value of the data object, create a subclass of DataTemplateSelector and override the SelectTemplate method. В следующем примере SelectTemplate метод предоставляет логику для возврата соответствующего шаблона на основе значения Priority свойства.In the following example, the SelectTemplate method provides logic to return the appropriate template based on the value of the Priority property. Возвращаемый шаблон находится в ресурсах элемента запечатывание Window .The template to return is found in the resources of the enveloping Window element.

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

Затем можно объявить TaskListDataTemplateSelector как ресурс:We can then declare the TaskListDataTemplateSelector as a resource:

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

Чтобы использовать ресурс селектора шаблона, назначьте его ItemTemplateSelector свойству ListBoxобъекта.To use the template selector resource, assign it to the ItemTemplateSelector property of the ListBox. ListBox ВызываетSelectTemplate метод дляTaskListDataTemplateSelector каждого элемента в базовой коллекции.The ListBox calls the SelectTemplate method of the TaskListDataTemplateSelector for each of the items in the underlying collection. Вызов передает объект данных в качестве параметра элемента.The call passes the data object as the item parameter. Объект DataTemplate , возвращаемый методом, затем применяется к этому объекту данных.The DataTemplate that is returned by the method is then applied to that data object.

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

С помощью селектора ListBox шаблона теперь отображается следующее:With the template selector in place, the ListBox now appears as follows:

Снимок экрана образца шаблонов данныхData templating sample screenshot

Это заключительный шаг нашего обсуждения данного примера.This concludes our discussion of this example. Полный пример см. в разделе Вводная часть примера стилизации и использования шаблонов.For the complete sample, see Introduction to Data Templating Sample.

Стилизация и использование шаблонов для ItemsControlStyling and Templating an ItemsControl

Несмотря на то, что не единственный тип элемента управления, DataTemplate с помощью которого можно использовать, это очень ItemsControl распространенный сценарий для привязки к коллекции. ItemsControlEven though the ItemsControl is not the only control type that you can use a DataTemplate with, it is a very common scenario to bind an ItemsControl to a collection. В разделе что входит в DataTemplate мы обсуждали, что определение DataTemplate должно быть связано только с представлением данных.In the What Belongs in a DataTemplate section we discussed that the definition of your DataTemplate should only be concerned with the presentation of data. Чтобы узнать, когда не подходит использовать, DataTemplate важно понимать различные свойства стиля и шаблона, предоставляемые. ItemsControlIn order to know when it is not suitable to use a DataTemplate it is important to understand the different style and template properties provided by the ItemsControl. Следующий пример предназначен для демонстрации функции каждого из этих свойств.The following example is designed to illustrate the function of each of these properties. В этом примере Привязка выполняется к той же Tasks коллекции, что и в предыдущем примере. ItemsControlThe ItemsControl in this example is bound to the same Tasks collection as in the previous example. Для демонстрационных целей все стили и шаблоны в этом примере объявлены встроенными.For demonstration purposes, the styles and templates in this example are all declared 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>

Ниже приведен снимок экрана примера при его просмотре:The following is a screenshot of the example when it is rendered:

Снимок экрана примера ItemsControlItemsControl example screenshot

Обратите внимание, что вместо ItemTemplateиспользования можно ItemTemplateSelectorиспользовать.Note that instead of using the ItemTemplate, you can use the ItemTemplateSelector. Пример см. в предыдущем разделе.Refer to the previous section for an example. Аналогично, вместо использования ItemContainerStyleможно ItemContainerStyleSelectorиспользовать.Similarly, instead of using the ItemContainerStyle, you have the option to use the ItemContainerStyleSelector.

Два других свойства, относящиеся к ItemsControl стилю, не показаны здесь, — GroupStyle и. GroupStyleSelectorTwo other style-related properties of the ItemsControl that are not shown here are GroupStyle and GroupStyleSelector.

Поддержка иерархических данныхSupport for Hierarchical Data

Пока мы только рассматривали как привязывать и отображать одну коллекцию.So far we have only looked at how to bind to and display a single collection. Иногда встречается коллекция, содержащая другие коллекции.Sometimes you have a collection that contains other collections. Класс предназначен для использования с HeaderedItemsControl типами для вывода таких данных. HierarchicalDataTemplateThe HierarchicalDataTemplate class is designed to be used with HeaderedItemsControl types to display such data. В следующем примере ListLeagueList является списком объектов League.In the following example, ListLeagueList is a list of League objects. Каждый объект League содержит Name и коллекцию объектов Division.Each League object has a Name and a collection of Division objects. Каждый Division содержит Name и коллекцию объектов Team, и каждый объект Team содержит Name.Each Division has a Name and a collection of Team objects, and each Team object has a 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>

В примере показано, что с помощью HierarchicalDataTemplateможно легко отобразить список данных, содержащих другие списки.The example shows that with the use of HierarchicalDataTemplate, you can easily display list data that contains other lists. Ниже приведен снимок экрана примера.The following is a screenshot of the example.

Снимок экрана образца HierarchicalDataTemplateHierarchicalDataTemplate sample screenshot

См. такжеSee also