はじめに
WPFでListBoxを使用した際に、データによって表示を変更したいことがあります。
そんなときは、TemplateSelectorを使用します。
サンプルデータ
public class SampleData
{
public int ID { get; set; }
public string SampleText { get; set; }
public string SampleText2 { get; set; }
}
public ObservableCollection<SampleData> SampleDatas
private void SetDatas()
{
SampleDatas = new ObservableCollection<SampleData>();
for (int i = 0; i < 10; i++)
{
SampleDatas.Add(new SampleData()
{
ID = i,
SampleText = $"さんぷるてきすと{i}",
SampleText2 = $"サンプルテキスト{i}"
});
}
}
これをたとえばIDの値によって表示するTextや文字色を変更してみます
View
Window.Resourcesを以下のように記述します
<Window.Resources>
<DataTemplate x:Key="IsChekedTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}"
Foreground="Red"/>
<TextBlock Text="{Binding SampleText}"
Foreground="Red"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="IsNotChekedTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}"
Foreground="Blue"/>
<TextBlock Text="{Binding SampleText2}"
Foreground="Blue"/>
</StackPanel>
</DataTemplate>
次にListBoxを以下のように記述します
<ListBox ItemsSource="{Binding SampleDatas}">
<ListBox.ItemTemplateSelector>
<local:ListBoxTemplateSelector
IsChekedTemplate="{StaticResource IsChekedTemplate}"
IsNotChekedTemplate="{StaticResource IsNotChekedTemplate}"/>
</ListBox.ItemTemplateSelector>
</ListBox>
TemplateSelectorクラス作成
以下のようにListBoxTemplateSelector を作成します
ここではIDの値が2で割り切れるかどうかで判別しています
public class ListBoxTemplateSelector : DataTemplateSelector
{
public DataTemplate IsChekedTemplate { get; set; }
public DataTemplate IsNotChekedTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item == null) return IsNotChekedTemplate;
var id = ((SampleData)item).ID;
if (id % 2 == 0)
{
return IsChekedTemplate;
}
else
{
return IsNotChekedTemplate;
}
}
}
チェックボックスなどの値でListBoxItemを変更したい場合
さきほどまではListBoxItemの値によって表示を変更する方法でしたが、アプリ開発していると、外部の値によってListBoxItemを変更したいということもあります。
こんな感じの機能です
こういうときはDataTriggerを使用すると簡単に実装できます
View
ここではViewModelは使用せずに機能するようにしています
<ListBox ItemsSource="{Binding SampleDatas}">
<ListBox.Style>
<Style TargetType="ListBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=IsCheckByDataTrigger, Path=IsChecked}"
Value="True">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}"
Margin="0,0,10,0"/>
<TextBlock Text="{Binding SampleText}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=IsCheckByDataTrigger, Path=IsChecked}"
Value="False">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ID}"
Foreground="Blue"
Margin="0,0,10,0"/>
<TextBlock Text="{Binding SampleText2}"
Foreground="Blue"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
ListBoxのStyle設定からDataTriggerを使用し、ItemTemplateを動的に変更できるようにしています。
今回はListBoxを例に挙げましたが、ContentControlに対して設定すれば、画面内そのものを変更するといったこともできます。
疑似的にページが切り替わったみたいな機能を実装できちゃったりします。
多用するとコードがごちゃごちゃするので気を付ける必要がありますが、覚えておくと結構便利かなと思います。