C#のWPFでListViewのアイテムを複数選択する。

コンピュータ

ListViewでShiftキーやコントロールキーを使って複数アイテムを選択した状態を検出する方法調べてみました。

プロジェクトの作成

ソースコード

ファイル名:FileEntity.cs

public class FileEntity
{
    public string Name { get; set; } = "";
    public bool IsSelected { get; set; } = false;
}

ファイル名:MainWindow.xaml

<Window x:Class="ListViewMultiSelect.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:i="clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors"
        xmlns:interactivity="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF"
        xmlns:local="clr-namespace:ListViewMultiSelect"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <ListView
            SelectionMode="Extended"
            ItemsSource="{Binding Files}">
            <ListView.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="メニュー1" Command="{Binding FilesListViewMenu1Command}" />
                </ContextMenu>
            </ListView.ContextMenu>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="IsSelected" Value="{Binding IsSelected}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ListView.View>
                <GridView>
                    <GridViewColumn>
                        <GridViewColumnHeader Content="名前" />
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

ファイル名:MainWindowViewModel.cs

using System;
using System.ComponentModel;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using System.Reactive.Disposables;

using System.Diagnostics;

namespace ListViewMultiSelect;

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    
    public ReactiveCollection<FileEntity> Files { get; set; } = [];
    public ReactiveCommand<EventArgs> FilesListViewMenu1Command { get; } = new();
    public MainWindowViewModel()
    {
        Files.AddOnScheduler(new FileEntity{ Name="A"});
        Files.AddOnScheduler(new FileEntity{ Name="B"});
        Files.AddOnScheduler(new FileEntity{ Name="C"});
        Files.AddOnScheduler(new FileEntity{ Name="D"});
        Files.AddOnScheduler(new FileEntity{ Name="E"});

        FilesListViewMenu1Command
            .Subscribe(e=>
            {
                // コンテキストメニュー1を実行
                Debug.Print($"コンテキストメニュー1");

                foreach(var f in Files)
                {
                    Debug.Print($"{f.Name} {f.IsSelected}");
                }
            }
        );
    }

}

実行

実行するとA~Eの文字がセットされたListViewが表示されます。

B~Dを選択します。

右クリックし「メニュー1」をクリックします。

アイテムの選択・非選択を「IsSelected」プロパティで確認出来ます。

ListViewのSelectionModeプロパティをExtendedセットすると複数選択が可能になります。
選択されたアイテムはIsSelectedプロパティがtrueになります。ということでIsSelectedプロパティがViewModelで参照することが出来れば複数行の選択されたアイテムを使ってプログラミングすることが出来ます。
ただ、ListViewのItemは動的に作成されるため通常のXAMLでは記述されていません。
Styleを使うことでListViewItemに対しIsSelectedプロパティをバインドするようにしてあります。この方法であれば動的に追加されるListViewItemに対するバインド処理を記述することが出来ます。
あとはListViewのデータソースであるFiles(FileEntity)にIsSelectedプロパティを用意しバンドしてあげれば、ViewModelから参照することが出来ました。

コメント