WPFのContentControlを使いListViewの選択Itemのクラスで編集UIを切り替える。

コンピュータ

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から選ばれる。

今回は切り替わるだけの動作確認のサンプルコードでしたが、実際アプリで使う場合は、

ItemBaseINotifyPropertyChangedの実装にする必要がありそうですね。

実質、バインディングを前提とした、WPFらしい機能だと思います。

自動的にDataTemplateが選ばれるのは唐突な感じもしますが、

切り替えのコードを自分で書く必要が無い点はあありがたい。


コメント