C#のListBoxでCheckBoxを並べてみた

C#のWPFで、ListBoxを使ってCheckBoxを並べてみました。CheckBoxを動的に追加したり削除したりしたいという試みです。 ListBoxでの選択とCheckBoxのチェック状態の一致はしません。CheckBoxを並べるだけです。

目次

  1. CheckBoxを並べてどうするのか
  2. 処理の流れ
  3. 試してみた
    1. XAML
    2. コード
    3. 動かしてみた

CheckBoxを並べてどうするのか

データの入力画面で、そのデータに関連する項目などを入力してもらうときにCheckBoxを使ったりします。項目が定まっているのであれば最初からその項目の数だけCheckBoxを並べておけばよいのですが、項目が増えたり減ったりする場合があります。動的にCheckBoxを増やしたり減らしたりすればよいのですが、レイアウトをいじるのは面倒かなと思いまして、CheckBoxをListBoxに入れてしまえと考えたわけです。

処理の流れ

  1. XAMLで、ListBoxのDataTemplateの子要素にCheckBox要素を記述する。

  2. データ保持用のクラスに、bool型のプロパティ(チェックの状態を保持)とstring型のプロパティ(項目を保持)を設定する。

  3. データ保持用のクラスのコレクションのインスタンスを、ObservableCollectionクラスのコレクションとして作る。

  4. ListBoxのItemSourceにデータ保持用のコレクションのインスタンスを設定する。

  5. CheckBoxのIsCheckedプロパティにデータ保持用クラスのbool型プロパティを、Contentプロパティにstring型プロパティをバインドする。

ListBoxのDataTemplateクラスでアイテムの見た目をCheckBoxに変更し、そのCheckBoxのプロパティにデータ内の対応するプロパティをバインドするというものです。

試してみた

ListBoxとButton3つとTextBlockを縦に並べました。「Add」ボタンをクリックするとListBoxにアイテムを追加し、「Delete」ボタンをクリックすると選択したアイテムを削除します。「Display Collection」ボタンをクリックすると、TextBlockにデータの中身を表示します。

XAML

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="200" Loaded="Window_Loaded">
    <Grid>
        <StackPanel>
            <ListBox Name="listbox" ItemsSource="{Binding}" Height="100" SelectionMode="Multiple">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <CheckBox IsChecked="{Binding Path=Chk}" Content="{Binding Path=Piyo}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <Button Name="buttonAdd" Content="Add" Click="buttonAdd_Click" />
            <Button Name="buttonDel" Content="Delete" Click="buttonDel_Click" />
            <Button Name="buttonDisplay" Content="Display Collection" Click="buttonDisplay_Click" />
            <TextBlock Name="textblock" />
        </StackPanel>
    </Grid>
</Window>

ListBoxのItemSourceをバインドにして、その子要素のCheckBoxのIsChecked属性とContent属性のバインドにPathを設定しました。

コード

こんなコードにしてみました。

using System.Collections.ObjectModel;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        ObservableCollection<Hoge> hoges = new ObservableCollection<Hoge>(); // コレクションのインスタンスを作る。

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            listbox.ItemsSource = hoges; // コレクションをListBoxにバインドする。
        }

        private void buttonAdd_Click(object sender, RoutedEventArgs e)
        {
            // ランダムな数字を作る。
            System.Random r = new System.Random();
            int i = r.Next(10);

            // ListBoxにアイテムを追加する。
            Hoge hoge = new Hoge();
            hoge.Chk = false;
            hoge.Piyo = "ぴよ" + i.ToString();
            hoges.Add(hoge);
        }

        private void buttonDel_Click(object sender, RoutedEventArgs e)
        {
            if (hoges.Count < 1) return; // コレクションの数が0の場合は何もしない。

            // ListBoxで選択されたアイテムを、別のコレクションにコピーする。
            Collection<Hoge> selected = new Collection<Hoge>();
            foreach (Hoge i in listbox.SelectedItems)
            {
                selected.Add(i);
            }
            // 元のコレクションから、選択されたアイテムと同じアイテムを削除する。
            foreach (Hoge item in selected)
            {
                hoges.Remove(item);
            }
        }

        private void buttonDisplay_Click(object sender, RoutedEventArgs e)
        {
            textblock.Text = string.Empty;
            foreach (Hoge item in hoges)
            {
                textblock.Text = textblock.Text + item.Chk.ToString() + " : " + item.Piyo + "\r\n";
            }
        }
    }

    public class Hoge
    {
        public bool Chk { get; set; }
        public string Piyo { get; set; }
    }
}

ListBoxのItemSourceにhogesというコレクションのインスタンスを設定しました。XAMLの方のPathの設定でプロパティを読みに行ってくれます。

動かしてみた

ビルドして実行してみました。

「Add」ボタンを4回クリックしてアイテムを4つ追加し、「ぴよ6」「ぴよ4」のチェックボックスをONにして、「Display Collection」ボタンをクリックした状態です。

image0

テキストブロックに表示されるデータの中身をみると、チェックボックスのオンオフがデータに反映されていることがわかります。

「ぴよ5」「ぴよ6」を選択して「Delete」ボタンをクリックし、「Display Collection」ボタンをクリックした状態です。

image1

アイテムが削除されるとデータも削除されることがわかります。

更新日
公開日

広告