Xamarin.Forms DataTemplate の作成

データ テンプレートは、ResourceDictionary 内でインラインで作成したり、またはカスタム型や適切な Xamarin.Forms のセルの種類から作成したりできます。 この記事では、各手法について説明します。

DataTemplate の一般的な使用シナリオは、ListView でオブジェクトのコレクションのデータを表示することです。 ListView の各セルのデータの外観は、ListView.ItemTemplate プロパティを DataTemplate に設定することで管理できます。 これを実現するために利用できる手法がいくつかあります。

使用する手法に関係なく、次のスクリーンショットに示すように、結果として ListView の各セルの外観は DataTemplate で定義されます。

DataTemplate を使用する ListView

インライン DataTemplate を作成する

ListView.ItemTemplate プロパティはインライン DataTemplate に設定できます。 インライン テンプレートは、適切なコントロール プロパティの直接の子として配置されるものであり、データ テンプレートを別の場所で再利用する必要がない場合に使用するようにします。 次の XAML コード例のように、DataTemplate に指定された要素で各セルの外観を定義します。

<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 か、そこから派生している必要があります。 この例では、Cell から派生した ViewCell が使われます。 ViewCell 内のレイアウトは Grid で管理されています。 Grid には 3 つの 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 引数を指定するコンストラクター オーバーロードを使用して作成されます。

Type を使用して 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>

ここでは、セルの外観を定義するカスタムの種類から作成された DataTemplateListView.ItemTemplate プロパティが設定されています。 次のコード例に示すように、カスタムの種類は、種類 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 には 3 つの 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;
    }
}

Note

Xamarin.Forms には、ListView セルに単純なデータを表示するために使用できるセルの種類も含まれています。 詳細については、セルの外観に関するページを参照してください。

リソースとして DataTemplate を作成する

データ テンプレートは、ResourceDictionary で再利用可能なオブジェクトとして作成することもできます。 これを実現するには、次の XAML コード例に示すように、ResourceDictionary 内に説明的なキーを提供する一意の x:Key 属性を各宣言に指定します。

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

StaticResource マークアップ拡張を使用して、DataTemplateListView.ItemTemplate プロパティに割り当てられます。 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 は、Add メソッドを使用して ResourceDictionary に追加されます。これで、取得時に DataTemplate を参照するために使用される Key 文字列が指定されます。

まとめ

この記事では、インライン、カスタムの種類、または ResourceDictionary でデータ テンプレートを作成する方法について説明しました。 データ テンプレートを他の場所で再利用する必要がない場合は、インライン テンプレートを使用する必要があります。 または、データ テンプレートをカスタム型として定義することで、あるいは制御レベル、ページ レベル、またはアプリケーション レベルのリソースとして定義することで、それを再利用できます。