C#WPFの道#10!ListViewの使い方をわかりやすく解説!

当サイトではアフィリエイト広告を利用しています。

WPF

ListViewとは?

ListViewはデータの一覧を表示するコントロールで、自由なレイアウトで一覧表を作ることができます。

ListViewの使い方

ListViewのItemsSourceプロパティにカスタムクラスのリスト等をセットすることで、一覧表が表示されます。

今回は顧客クラスである「Customer」クラスを作成し、ID、名前、電話番号を一覧表示する例を見ていきましょう。

ItemsSourceプロパティでの一覧表示

Xaml

それではまず画面レイアウトを作成します。画面レイアウトにはデータ追加用のAddボタンとListViewを設置します。AddボタンにはClickイベントを生成しておきます。

<Window x:Class="WPF010.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:WPF010"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <StackPanel Margin="10">
            <Button x:Name="AddButton"
                    Content="Add"
                    FontSize="30"
                    Click="AddButton_Click"/>

            <ListView x:Name="CustomerListView"
                      Margin="0,5,0,0">
                
            </ListView>

        </StackPanel>
    </Grid>
</Window>

<Xamlで生成される画面イメージ>

Customerクラスの作成

顧客クラスの一覧を表示するために、1データに相当するクラス「Customer」クラスを作成します。ID、名前、電話番号のプロパティがあるだけのシンプルなクラスです

namespace WPF010
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Phone { get; set; }
    }
}

MainWindowのコードビハインド側

コードビハインド側では、Customerクラスのリストのフィールド作成し、コンストラクタでデータを3件追加しています。その後にListViewのItemsSourceプロパティに_customersインスタンスをセットしています。

using System.Collections.Generic;
using System.Windows;

namespace WPF010
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private List<Customer> _customers = new List<Customer>();

        public MainWindow()
        {
            InitializeComponent();

            _customers.Add(new Customer { Id = 1, Name = "name1", Phone = "phone1" });
            _customers.Add(new Customer { Id = 2, Name = "name2", Phone = "phone2" });
            _customers.Add(new Customer { Id = 3, Name = "name3", Phone = "phone3" });

            CustomerListView.ItemsSource = _customers;
        }

        private void AddButton_Click(object sender, RoutedEventArgs e)
        {

        }
    }
}

<実行結果>

実行すると、データは3件表示されますが、「WPF010.Customer」と表示されてしまっています。これでは使いものになりません。これはCustomerクラスのToString()された文字列が表示されているためです。これの解決方法とみていきたいと思います。

CustomerクラスのToString()問題の解決

次のようにCustomerクラスにToString()メソッドをオーバーライドすることで、任意の文字列を表示することができます。この場合、ToString()されると、ID、名前、電話番号がハイフン区切りで文字列が生成されます。

namespace WPF010
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Phone { get; set; }

        public override string ToString()
        {
            return $"{Id} - {Name} - {Phone}";
        }
    }
}

<実行結果>

これで、データを表示することができました。ID、名前、電話番号がハイフン区切りで表示されています。しかし、これだと表現力が低すぎますよね?もっと自由にレイアウトしたいという要望が通常はあると思います。例えば、名前の文字の大きさを大きくして、電話番号は青文字で表示したいなどです。こういった問題に対する対応をTextBlockとBindingという機能を使って解決していきます。

ItemTemplateとDataTemplateとBinding

ListViewに対するXamlを次のように定義します。まずListView.ItemTemplateブロックを記述し、その中にDataTemplateブロックを作ります。その中にStackPanelで自由にコントロールを配置していきます。今回はID、名前、電話番号の3つの表示ですから、それらのすべてをTextBlockで設定します。それぞれのTextBlockに何を表示するかを設定する必要があるのでText=”{Binding Id}”のようにして、Customerクラスのどの値を表示するかを指定します。フォントのサイズや文字の色などを変更したい場合は、TextBlockのそれらのプロパティを変更するだけでよいので、自由なレイアウトを作成することができます。

<Window x:Class="WPF010.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:WPF010"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <StackPanel Margin="10">
            <Button x:Name="AddButton"
                    Content="Add"
                    FontSize="30"
                    Click="AddButton_Click"/>

            <ListView x:Name="CustomerListView"
                      Margin="0,5,0,0">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Id}"/>
                            <TextBlock Text="{Binding Name}" FontSize="20"/>
                            <TextBlock Text="{Binding Phone}" Foreground="Blue"/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

        </StackPanel>
    </Grid>
</Window>

<実行結果>

これで自由にレイアウトすることができるようになりました。

Addボタンの実装

_indexフィールドの追加

Addボタンが押されたときに、データが追加されていく実装を行います。MainWindowのコードビハインド側に自動生成されているAddButton_Clickイベントに、ボタンを押すたびに、Customerクラスが追加されるように記述します。また、連番で追加されるように_indexフィールドを作成して、コンストラクタで追加している3件のデータも一部変更しています。

ObservableCollectionの利用

CustomerクラスのリストのフィールドをList<T>で宣言していましたが、それではAddボタンをクリックしてデータを追加しても変更通知が行われず、画面が変化しないため、ObservableCollectionに変更しています。このクラスを使用すると、データの変更通知が行われるため、画面が変更されます。

 

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

namespace WPF010
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<Customer> _customers = new ObservableCollection<Customer>();
        private int _index = 0;
        public MainWindow()
        {
            InitializeComponent();

            _customers.Add(
new Customer { Id = ++_index, Name = "name" + _index, Phone = "phone" + _index });
            _customers.Add(
new Customer { Id = ++_index, Name = "name" + _index, Phone = "phone" + _index });
            _customers.Add(
new Customer { Id = ++_index, Name = "name" + _index, Phone = "phone" + _index });

            CustomerListView.ItemsSource = _customers;
        }

        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            _customers.Add(
new Customer { Id = ++_index, Name = "name" + _index, Phone = "phone" + _index });
        }
    }
}

<実行結果>

Addボタンを押下するたびにデータが追加されるようになりました。しかし、スクロールバーが出てきませんよね?これに対しては、ListViewのHeightプロパティを設定することで解決できます。

スクロールバーが出ない問題

ListViewのHeightプロパティを設定することでスクロールバーが表示されるようになります。

<Window x:Class="WPF010.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:WPF010"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <StackPanel Margin="10">
            <Button x:Name="AddButton"
                    Content="Add"
                    FontSize="30"
                    Click="AddButton_Click"/>

            <ListView x:Name="CustomerListView"
                      Margin="0,5,0,0"
                      Height="250">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Id}"/>
                            <TextBlock Text="{Binding Name}" FontSize="20"/>
                            <TextBlock Text="{Binding Phone}" Foreground="Blue"/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

        </StackPanel>
    </Grid>
</Window>

<実行結果>