Поделиться через


Создание Xamarin.Forms DataTemplate

Шаблоны данных могут создаваться как встроенные в ResourceDictionary или из пользовательского типа или соответствующего типа ячейки Xamarin.Forms. В этой статье рассматривается каждый из способов.

Стандартный сценарий использования DataTemplate — отображение данных из коллекции объектов в ListView. Внешним видом данных в каждой ячейке ListView можно управлять, присваивая свойству ListView.ItemTemplate объект DataTemplate. Это можно делать несколькими способами:

Какой бы способ ни использовался, в результате внешний вид каждой ячейки ListView определяется шаблоном DataTemplate, как показано на следующих снимках экрана.

ListView с шаблоном DataTemplate

Создание встроенного шаблона DataTemplate

Свойству ListView.ItemTemplate может быть присвоен встроенный шаблон DataTemplate. Встроенный шаблон, который является прямым потомком соответствующего свойства элемента управления, следует использовать, если нет необходимости повторно использовать шаблон данных в другом месте. Элементы шаблона DataTemplate определяют внешний вид каждой ячейки, как показано в следующем примере кода XAML.

<ListView Margin="0,20,0,0">
    <ListView.ItemsSource>
        <x:Array Type="{x:Type local:Person}">
            <local:Person Name="Steve" Age="21" Location="USA" />
            <local:Person Name="John" Age="37" Location="USA" />
            <local:Person Name="Tom" Age="42" Location="UK" />
            <local:Person Name="Lucas" Age="29" Location="Germany" />
            <local:Person Name="Tariq" Age="39" Location="UK" />
            <local:Person Name="Jane" Age="30" Location="USA" />
        </x:Array>
    </ListView.ItemsSource>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Grid>
                    ...
                    <Label Text="{Binding Name}" FontAttributes="Bold" />
                    <Label Grid.Column="1" Text="{Binding Age}" />
                    <Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Дочерний объект встроенного шаблона DataTemplate должен иметь тип Cell или производный от него тип. В этом примере используется класс ViewCell, производный от Cell. Управление макетом внутри ViewCell осуществляется здесь с помощью Grid. Макет Grid содержит три экземпляра Label, свойства Text которых привязаны к соответствующим свойствам каждого объекта Person в коллекции.

Эквивалентный код на языке C# показан в следующем примере:

public class WithDataTemplatePageCS : ContentPage
{
    public WithDataTemplatePageCS()
    {
        ...
        var people = new List<Person>
        {
            new Person { Name = "Steve", Age = 21, Location = "USA" },
            ...
        };

        var personDataTemplate = new DataTemplate(() =>
        {
            var grid = new Grid();
            ...
            var nameLabel = new Label { FontAttributes = FontAttributes.Bold };
            var ageLabel = new Label();
            var locationLabel = new Label { HorizontalTextAlignment = TextAlignment.End };

            nameLabel.SetBinding(Label.TextProperty, "Name");
            ageLabel.SetBinding(Label.TextProperty, "Age");
            locationLabel.SetBinding(Label.TextProperty, "Location");

            grid.Children.Add(nameLabel);
            grid.Children.Add(ageLabel, 1, 0);
            grid.Children.Add(locationLabel, 2, 0);

            return new ViewCell { View = grid };
        });

        Content = new StackLayout
        {
            Margin = new Thickness(20),
            Children = {
                ...
                new ListView { ItemsSource = people, ItemTemplate = personDataTemplate, Margin = new Thickness(0, 20, 0, 0) }
            }
        };
    }
}

На C# встроенный шаблон DataTemplate создается с помощью перегрузки конструктора, задающей аргумент Func.

Создание шаблона DataTemplate с типом

Свойству ListView.ItemTemplate также может присваиваться шаблон DataTemplate, созданный из типа ячейки. Преимуществом этого подхода является возможность повторного использования внешнего вида, определяемого типом ячейки, в нескольких шаблонах данных в приложении. Пример такого подхода показан в следующем коде XAML.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataTemplates"
             ...>
    <StackLayout Margin="20">
        ...
        <ListView Margin="0,20,0,0">
           <ListView.ItemsSource>
                <x:Array Type="{x:Type local:Person}">
                    <local:Person Name="Steve" Age="21" Location="USA" />
                    ...
                </x:Array>
            </ListView.ItemsSource>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <local:PersonCell />
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

В этом случае свойству ListView.ItemTemplate присвоен шаблон DataTemplate, созданный на основе пользовательского типа, который определяет внешний вид ячейки. Пользовательский тип должен быть производным от типа ViewCell, как показано в следующем примере кода.

<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
          x:Class="DataTemplates.PersonCell">
     <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.5*" />
            <ColumnDefinition Width="0.2*" />
            <ColumnDefinition Width="0.3*" />
        </Grid.ColumnDefinitions>
        <Label Text="{Binding Name}" FontAttributes="Bold" />
        <Label Grid.Column="1" Text="{Binding Age}" />
        <Label Grid.Column="2" Text="{Binding Location}" HorizontalTextAlignment="End" />
    </Grid>
</ViewCell>

Управление макетом внутри ViewCell осуществляется здесь с помощью Grid. Макет Grid содержит три экземпляра Label, свойства Text которых привязаны к соответствующим свойствам каждого объекта Person в коллекции.

Эквивалентный код на языке C# показан в следующем примере.

public class WithDataTemplatePageFromTypeCS : ContentPage
{
    public WithDataTemplatePageFromTypeCS()
    {
        ...
        var people = new List<Person>
        {
            new Person { Name = "Steve", Age = 21, Location = "USA" },
            ...
        };

        Content = new StackLayout
        {
            Margin = new Thickness(20),
            Children = {
                ...
                new ListView { ItemTemplate = new DataTemplate(typeof(PersonCellCS)), ItemsSource = people, Margin = new Thickness(0, 20, 0, 0) }
            }
        };
    }
}

На C# шаблон DataTemplate создается с помощью перегрузки конструктора, задающей тип ячейки в качестве аргумента. Тип ячейки должен быть производным от типа ViewCell, как показано в следующем примере кода.

public class PersonCellCS : ViewCell
{
    public PersonCellCS()
    {
        var grid = new Grid();
        ...
        var nameLabel = new Label { FontAttributes = FontAttributes.Bold };
        var ageLabel = new Label();
        var locationLabel = new Label { HorizontalTextAlignment = TextAlignment.End };

        nameLabel.SetBinding(Label.TextProperty, "Name");
        ageLabel.SetBinding(Label.TextProperty, "Age");
        locationLabel.SetBinding(Label.TextProperty, "Location");

        grid.Children.Add(nameLabel);
        grid.Children.Add(ageLabel, 1, 0);
        grid.Children.Add(locationLabel, 2, 0);

        View = grid;
    }
}

Примечание.

Обратите внимание на то, что в Xamarin.Forms также есть типы ячеек, которые позволяют отображать простые данные в ячейках ListView. Дополнительные сведения см. в статье Настройка внешнего вида ячейки.

Создание шаблона DataTemplate как ресурса

Шаблоны данных также можно создавать как повторно используемые объекты в ResourceDictionary. Для этого каждому объявлению присваивается уникальный атрибут x:Key, который предоставляет описательный ключ в ResourceDictionary, как показано в следующем примере кода XAML.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             ...>
    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="personTemplate">
                 <ViewCell>
                    <Grid>
                        ...
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Margin="20">
        ...
        <ListView ItemTemplate="{StaticResource personTemplate}" Margin="0,20,0,0">
            <ListView.ItemsSource>
                <x:Array Type="{x:Type local:Person}">
                    <local:Person Name="Steve" Age="21" Location="USA" />
                    ...
                </x:Array>
            </ListView.ItemsSource>
        </ListView>
    </StackLayout>
</ContentPage>

Шаблон DataTemplate присваивается свойству ListView.ItemTemplate с помощью расширения разметки StaticResource. Обратите внимание на то, что шаблон DataTemplate может определяться не только в объекте ResourceDictionary страницы, но и на уровне элемента управления или приложения.

В следующем примере кода показана эквивалентная страница на языке C#:

public class WithDataTemplatePageCS : ContentPage
{
  public WithDataTemplatePageCS ()
  {
    ...
    var personDataTemplate = new DataTemplate (() => {
      var grid = new Grid ();
      ...
      return new ViewCell { View = grid };
    });

    Resources = new ResourceDictionary ();
    Resources.Add ("personTemplate", personDataTemplate);

    Content = new StackLayout {
      Margin = new Thickness(20),
      Children = {
        ...
        new ListView { ItemTemplate = (DataTemplate)Resources ["personTemplate"], ItemsSource = people };
      }
    };
  }
}

Шаблон DataTemplate добавляется в ResourceDictionary с помощью метода Add, задающего строку Key. По ней можно ссылаться на шаблон DataTemplate, который нужно извлечь.

Итоги

В этой статье были представлены сведения о создании шаблонов данных как встроенных, на основе пользовательского типа или в ResourceDictionary. Встроенный шаблон следует использовать, если нет необходимости повторно использовать шаблон данных в другом месте. Шаблон данных можно использовать повторно, определив его как пользовательский тип или как ресурс на уровне элемента управления, страницы или приложения.