DataTemplateを使うと、ContentControlの中身を切り替えることが出来るので、
ListViewの選択したItemのクラスでUIを切り替えるサンプルコードを作成しました。
実行例:
左側はListViewで、「タイトル」「明るさ」がItemとして並びます。
「タイトル」を選択すると、右側はテキストボックスで文字列が編集可能。
「明るさ」を選択すると、右側はすラダーで数値が編集可能になります。
DataTemplateでContentControlの中身が入れ替わることで、動的にUIが切り替わる機能を実現しています。
ItemBase.cs
namespace ContentControlDemo;
// ItemBase.cs
public abstract class ItemBase
{
public string Name { get; set; } = "";
}
// TextItem.cs
public class TextItem : ItemBase
{
public string Value { get; set; } = "";
}
// NumberItem.cs
public class NumberItem : ItemBase
{
public double Value { get; set; }
}
MainViewModel.cs
// MainViewModel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ContentControlDemo;
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<ItemBase> Items { get; } =
[
new TextItem { Name="タイトル", Value="Hello" },
new NumberItem { Name="明るさ", Value=50 }
];
ItemBase? _selectedItem = null;
public ItemBase? SelectedItem
{
get => _selectedItem;
set { _selectedItem = value; OnPropertyChanged(); }
}
public event PropertyChangedEventHandler? PropertyChanged;
void OnPropertyChanged([CallerMemberName] string? name=null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
MainWindow.xaml
<Window x:Class="ContentControlDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ContentControlDemo"
mc:Ignorable="d"
Title="Sample" Width="700" Height="400">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<!-- 右側:TextItem の編集UI -->
<DataTemplate DataType="{x:Type local:TextItem}">
<StackPanel Margin="8">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Margin="0,0,0,6"/>
<TextBox Text="{Binding Value}" Width="250"/>
</StackPanel>
</DataTemplate>
<!-- 右側:NumberItem の編集UI -->
<DataTemplate DataType="{x:Type local:NumberItem}">
<StackPanel Margin="8">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Margin="0,0,0,6"/>
<Slider Value="{Binding Value}" Minimum="0" Maximum="100" Width="250"/>
<TextBlock Text="{Binding Value}" Margin="0,6,0,0"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="260"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- 左:ListView(見た目は統一してTextBlockだけ) -->
<ListView Grid.Column="0"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Padding="6"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- 右:ContentControl(選択されたItemを型別テンプレで編集表示) -->
<Border Grid.Column="1" BorderBrush="#DDD" BorderThickness="1" Margin="8">
<ContentControl Content="{Binding SelectedItem}"/>
</Border>
</Grid>
</Window>
ContentControlでListViewのSelectedItemをバインディングしているだけで、然るべきクラスのUIがWindow.ResourcesのDataTemplateから選ばれる。
今回は切り替わるだけの動作確認のサンプルコードでしたが、実際アプリで使う場合は、
ItemBaseもINotifyPropertyChangedの実装にする必要がありそうですね。
実質、バインディングを前提とした、WPFらしい機能だと思います。
自動的にDataTemplateが選ばれるのは唐突な感じもしますが、
切り替えのコードを自分で書く必要が無い点はあありがたい。

コメント