ListViewの項目に対して異なるテンプレートを適用する
ListViewやCollectionViewといったコレクションをリスト表示する系のコントロールは,各項目の見た目をDataTemplate
で定義します.
これによって好きな各項目を任意の見た目で表示することができます.
このDataTemplate
による見た目の指定はシンプルに使えばすべての項目に同じ見た目が適用されるのですが,任意の条件で適用するテンプレートを切り替えることもでき,より豊かな表現ができるようになっています.
今回紹介するのは複数のテンプレートを定義して,それを動的に変更する方法です.
何かしらの条件に応じて項目のテンプレートを切り替える場合,DataTemplateSelector
を使います.
複数のDataTemplateを用意する
切り替えるテンプレートをResource
に用意します.ContentPage.Resources
内に定義していますが,アクセスできる場所であればどこでもOkです.
ここでは2つ用意し,それぞれfirstTemplate
とsecondTemplate
という名前をつけます.
注意したいのは,今回使うのはListViewなのでDataTemplate
の中にViewCell
(など)を置く必要があります.これはCollectionView
では必要ありません.
<ContentPage.Resources> <!-- First Template --> <DataTemplate x:Key="firstTemplate"> <ViewCell> <Grid> <Label FontSize="Title" Text="FirstTemplate!" /> <Image HeightRequest="50" Source="myIcon" WidthRequest="50" /> <Label FontSize="Large" HorizontalOptions="End" Text="{Binding TemplateId}" /> </Grid> </ViewCell> </DataTemplate> <!-- Second Template --> <DataTemplate x:Key="secondTemplate"> <ViewCell> <StackLayout> <Label FontSize="Large" Text="SecondTemplate!" TextColor="Red" /> <CheckBox /> <Label FontSize="Large" Text="{Binding TemplateId}" /> </StackLayout> </ViewCell> </DataTemplate> </ContentPage.Resources>
1つ目のテンプレートはラベルと画像とラベルが表示され,2つ目のテンプレートはラベルとチェックボックスとラベルが縦に並ぶ,という内容になっています. データバインディングも使ってあります.
テンプレートを切り替えるロジックを書く
この2つのテンプレートを切り替える条件をC#側で用意します.
MyDataTemplateSelector
と名前をつけるとします.
public class MyDataTemplateSelector : DataTemplateSelector { //切り替えるテンプレートを保持するプロパティを用意する public DataTemplate FirstTemplate { get; set; } public DataTemplate SecondTemplate { get; set; } protected override DataTemplate OnSelectTemplate(object item, BindableObject container) { //ここに条件を書き //条件にマッチするプロパティ(DataTemplate)を返す return ((MyItem)item).TemplateId==0 ? FirstTemplate : SecondTemplate; //itemパラメータにはXaml側から各項目にバインドされたオブジェクト //今回はMyItemオブジェクトが入ってくる //今回はそれを利用してテンプレートを切り替える } }
ListViewにバインディングするデータは以下とします.
public class MyItem { public int TemplateId { get; set; } }
public List<MyItem> ItemList { get; set; } public MainPage() { InitializeComponent(); ItemList = new List<MyItem>(); for (int i = 0; i < 50; i++) { ItemList.Add(new MyItem { //0と1が交互に割り当てられる TemplateId = i % 2 }); ; } this.BindingContext = this; }
作ったDatatemplateSelectorをXAML側で指定する
まずはテンプレートセレクターをXAML側で参照できるようにテンプレートセレクターの名前空間を追加します.
ページのトップの要素,今回の例ではContentPage
,に以下の1行を追加します.
xmlns:local="clr-namespace:XFCarouselPractice"
こんな感じになると思います.
<ContentPage x:Class="XFCarouselPractice.MainPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XFCarouselPractice" mc:Ignorable="d">
そうすると,local
というプレフィクスでMyDataTemplateSelector
にアクセスできるようになります.インテリセンスにも表示されます.
このMyDataTemplateSelector
はFirstTemplate
とSecondTemplate
という2つのプロパティがあり,それぞれにテンプレートを割り当てます.
<local:MyDataTemplateSelector x:Key="myDataTemplateSelector" FirstTemplate="{StaticResource firstTemplate}" SecondTemplate="{StaticResource secondTemplate}"/>
↓インテリセンスもきく.
これで準備は完了です.XAML側はこんな感じになります.
<ContentPage.Resources> <!-- First Template --> <DataTemplate x:Key="firstTemplate"> <ViewCell> <Grid> <Label FontSize="Title" Text="FirstTemplate!" /> <Image HeightRequest="50" Source="myIcon" WidthRequest="50" /> <Label FontSize="Large" HorizontalOptions="End" Text="{Binding TemplateId}" /> </Grid> </ViewCell> </DataTemplate> <!-- Second Template --> <DataTemplate x:Key="secondTemplate"> <ViewCell> <StackLayout> <Label FontSize="Large" Text="SecondTemplate!" TextColor="Red" /> <CheckBox /> <Label FontSize="Large" Text="{Binding TemplateId}" /> </StackLayout> </ViewCell> </DataTemplate> <local:MyDataTemplateSelector x:Key="myDataTemplateSelector" FirstTemplate="{StaticResource firstTemplate}" SecondTemplate="{StaticResource secondTemplate}" /> </ContentPage.Resources>
使う
ListViewにItemsSourceプロパティにItemListをバインディングして,ItemTemplateにmyDataTemplateSelector
(キー名)を指定します.
<ListView HasUnevenRows="True" ItemTemplate="{StaticResource myDataTemplateSelector}" ItemsSource="{Binding ItemList}" />
実行します.
交互にFirstTemplateとSecondTemplateの内容が表示されているのがわかると思います.
データバインドもされています.