環境
- Winui3 アプリ
準備:
/// アイテム public partial class MyClass : ObservableRecipient { [ObservableProperty] public string name = string.Empty; [ObservableProperty] public string description = string.Empty; [ObservableProperty] public int index = -1; }
/// ViewModel public class MainViewModel : ObservableRecipient { // ## 3 で使う public bool IsMode { get; set; } public ObservableCollection<MyClass> MyArray = new(); public MainViewModel() { foreach (var item in Enumerable.Range(1, 100)) { MyArray.Add(item: new MyClass() { Name = string.Format("Yamada-{0:000}", item), Index = item }); ; ; } } }
1:StyleSelector を使う
/// セレクター public class MySelector : StyleSelector { public Style? Style1 { get; set; } public Style? Style2 { get; set; } protected override Style? SelectStyleCore(object item, DependencyObject container) { if (item is MyClass myClass) { if (myClass.Index % 2 == 0) { return Style1; } else { return Style2; } } return base.SelectStyleCore(item, container); } }
<Page.Resources> <Style x:Key="MyStyle1" TargetType="ListViewItem"> <Setter Property="Background" Value="AliceBlue" /> </Style> <Style x:Key="MyStyle2" TargetType="ListViewItem"> <Setter Property="Background" Value="LightYellow" /> </Style> <views:MySelector x:Key="MySelectorListview" Style1="{StaticResource MyStyle1}" Style2="{StaticResource MyStyle2}" /> </Page.Resources>
<ListView Grid.Row="1" ItemContainerStyleSelector="{StaticResource MySelectorListview}" ItemsSource="{x:Bind Path=ViewModel.MyArray}"> <ListView.ItemTemplate> <DataTemplate x:DataType="viewmodels:MyClass"> <StackPanel Orientation="Horizontal"> <TextBlock Width="25" Text="{x:Bind Path=Index}" /> <TextBlock Width="150" Text="{x:Bind Path=Name}" /> <TextBlock Text="{x:Bind Path=Description}" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView>
2:DataTemplateSelector を使う
// コレクションの各アイテムのテンプレートを、コレクションの要素によって切り替えるクラス public class MyTemplateSelector : DataTemplateSelector { // テンプレートのプロパティ public DataTemplate MyTemplate { get; set; } public DataTemplate DefaultTemplate { get; set; } // コレクションの要素に応じてテンプレートを選択するメソッド protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { if (item is MyClass myClass) { if (myClass.Index % 2 == 0) { return DefaultTemplate; } else { return MyTemplate; } } return DefaultTemplate; } }
<DataTemplate x:Key="MyTemp1" x:DataType="viewmodels:MyClass"> <StackPanel Background="AliceBlue" Orientation="Horizontal"> <TextBlock Width="25" Text="{x:Bind Path=Index}" /> <TextBlock Width="150" Text="{x:Bind Path=Name}" /> <TextBlock Text="{x:Bind Path=Description}" /> </StackPanel> </DataTemplate> <DataTemplate x:Key="MyTemp2" x:DataType="viewmodels:MyClass"> <StackPanel Background="LightYellow" Orientation="Horizontal"> <TextBlock Width="25" Text="{x:Bind Path=Index}" /> <TextBlock Width="150" Text="{x:Bind Path=Name}" /> <TextBlock Text="{x:Bind Path=Description}" /> </StackPanel> </DataTemplate> <views:MyTemplateSelector x:Key="MyTemplateSelector" DefaultTemplate="{StaticResource MyTemp1}" MyTemplate="{StaticResource MyTemp2}" />
<ListView Grid.Row="1" ItemTemplateSelector="{StaticResource MyTemplateSelector}" ItemsSource="{x:Bind Path=ViewModel.MyArray}" />
3: IValueConverter → DataTemplateSelector を使う
動的にセレクターを切り替えたい
public class ModeToSelectorConvertor : IValueConverter { public DataTemplateSelector? MySelector { get; set; } public DataTemplateSelector? DefaultSelector { get; set; } public object Convert(object value, Type targetType, object parameter, string language) { if (value is bool iMode) { if (iMode) { return MySelector; } else { return DefaultSelector; } } return this.DefaultSelector!; } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }
<DataTemplate x:Key="MyTemp1" x:DataType="viewmodels:MyClass"> <StackPanel Background="AliceBlue" Orientation="Horizontal"> <TextBlock Width="25" Text="{x:Bind Path=Index}" /> <TextBlock Width="150" Text="{x:Bind Path=Name}" /> <TextBlock Text="{x:Bind Path=Description}" /> </StackPanel> </DataTemplate> <DataTemplate x:Key="MyTemp2" x:DataType="viewmodels:MyClass"> <StackPanel Background="LightYellow" Orientation="Horizontal"> <TextBlock Width="25" Text="{x:Bind Path=Index}" /> <TextBlock Width="150" Text="{x:Bind Path=Name}" /> <TextBlock Text="{x:Bind Path=Description}" /> </StackPanel> </DataTemplate> <DataTemplate x:Key="MyTemp3" x:DataType="viewmodels:MyClass"> <StackPanel Background="OrangeRed" Orientation="Horizontal"> <TextBlock Width="25" Text="{x:Bind Path=Index}" /> <TextBlock Width="150" Text="{x:Bind Path=Name}" /> <TextBlock Text="{x:Bind Path=Description}" /> </StackPanel> </DataTemplate> <views:MyTemplateSelector x:Key="MyTemplateSelector" DefaultTemplate="{StaticResource MyTemp1}" MyTemplate="{StaticResource MyTemp2}" /> <views:MyTemplateSelector x:Key="MyTemplateSelector2" DefaultTemplate="{StaticResource MyTemp1}" MyTemplate="{StaticResource MyTemp3}" /> // コンバーター → セレクター <views:ModeToSelectorConvertor x:Key="MyModeToSelectorConvertor" DefaultSelector="{StaticResource MyTemplateSelector}" MySelector="{StaticResource MyTemplateSelector2}" />
<ListView Grid.Row="1" ItemTemplateSelector="{x:Bind Path=ViewModel.IsMode, Mode=OneWay, Converter={StaticResource MyModeToSelectorConvertor}}" ItemsSource="{x:Bind Path=ViewModel.MyArray}" />
もう少しスマートな方法がある気がするが…。
以上