【C#入門】ListViewの使い方(項目の追加、ソートやスクロールの設定)

こんにちは!フリーランスの長野です。

ListViewって使ってますか?ListViewはGUIで表データを表示する場合に使うコントロールです。WPFでもListViewを使うことができます。ちなみにWPFとはHTMLに似た感覚で外観デザインを開発することができるGUI開発ライブラリのことです。

この記事では、WPFのListViewについて

  • ListViewとは
  • ListViewの使い方
  • 項目を追加する方法
  • スクロールで表示する方法
  • カラムでソートする方法

など基本的な内容から、実用的な使い方についても解説していきます。

今回はWPFのListViewについて、使い方をわかりやすく解説します。

目次

ListViewとは

ListViewはGUIで表データを表示する場合に使うコントロールのことです。C#でGUI開発を行う場合、WindowsフォームとWPFの2種類があります。WindowsフォームはC言語などで使われるWin32 APIを継承しているのに対して、WPFはWin32 APIとは無関係で新たに実装されたGUI開発ライブラリです。

WPFはUI(ユーザー・インターフェイス)要素に拡大・縮小/回転などを掛けることができて、柔軟にカスタマイズできるなどの点で便利なGUI開発ライブラリです。

ListViewコントロールは、Windowsフォーム、WPFのどちらでも利用できますが、今回はWPFのListViewについてご紹介していきます。

ListViewの使い方

まずはWPFの使い方ですが、こちらで詳しく解説しているので参考にしてください。

ListViewコントロールは「ツールボックス」の「すべてのWPFコントロール」からドラッグ&ドロップすることで使えるようになります。

c#_listview01

XAMLファイルには自動でListViewタグ、ListView.Viewタグ、GridViewタグ、GridViewColumnタグが記述されます。

c#_listview02

これでListViewコントロールを使えるようになります。

項目を追加する方法

ここではBindingを使ってソースコードでまとめて入力する方法について解説します。

WPFにはデータ・バインディングという機能があります。これは表示するデータに不整合がないか検証する機能と外観デザインとを分離する仕組みです。

データ・バインディングでは、外観デザインには「ここにはこのデータを表示する」という目印を入れるだけで、実際のデータは別のファイルから提供します。

まず、データを格納するクラスを作成します。ここでは、Testクラスを作成します。

Test.cs:

public class Test {
        public string Subj { get; set; }
        public int Points { get; set; }
        public string Name { get; set; }
        public string ClassName { get; set; }
}

このクラスのリストを作成するTestListクラスを作成します。

TestList.cs:

using System.Collections.ObjectModel;
 
public class TestList {
        // バインディングの指定先プロパティ
        public ObservableCollection<Test> Data { get; }
 
        // コンストラクタ(データ入力)
        public TestList() {
            Data = new ObservableCollection<Test> {
                new Test { Subj="国語", Points=90, Name="田中 一郎", ClassName="A" },
                new Test { Subj="数学", Points=50, Name="鈴木 二郎", ClassName="A" },
                new Test { Subj="英語", Points=90, Name="佐藤 三郎", ClassName="B" }
            };
        }       
 }

MainWindowクラスのコンストラクタでTestListクラスをインスタンス化します。

MainWindow.xaml.cs:

public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();

            TestList testList = new TestList();
            listView.DataContext = testList.Data;
        }
}

XAMLファイルでは、ListViewコントロールのItemsSourceプロパティに格納する値を取得するためにバインディングを使っています。

MainWindowクラスのコンストラクタでTestListクラスをインスタンス化しているので、TestListクラスのDataプロパティから取得できています。

MainWindow.xaml(一部のみ):

<ListView ItemsSource="{Binding}" x:Name="listView" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="教科" DisplayMemberBinding="{Binding Path=Subj}" Width="50"/>
                    <GridViewColumn Header="点数" DisplayMemberBinding="{Binding Path=Points}" Width="50"/>
                    <GridViewColumn Header="氏名" DisplayMemberBinding="{Binding Path=Name}" Width="100"/>
                    <GridViewColumn Header="クラス名" DisplayMemberBinding="{Binding Path=ClassName}" Width="50"/>
                </GridView>
            </ListView.View>
</ListView>

実行結果:
c#_wpf09

バインディングについても、こちらで詳しく解説していますので、ぜひ参考にしてください。

スクロールで表示する方法

ListViewコントロールの表示サイズに対して、データ量が多い場合などは全てのデータを表示しきれないこともあります。

そんな場合、ScrollViewer.HorizontalScrollBarVisibilityプロパティやScrollViewer.VerticalScrollBarVisibilityプロパティでスクロールできるように設定します。

横方向にスクロールする場合は、ScrollViewer.HorizontalScrollBarVisibilityプロパティを「Auto」もしくは「Visible」に設定します。縦方向にスクロールする場合は、ScrollViewer.VerticalScrollBarVisibilityプロパティを「Auto」もしくは「Visible」に設定します。

デフォルトの設定では「Auto」になっていますので、表示するデータ量が多く収まらなくなると自動でスクロールバーが表示されます。

c#_listview03

カラムでソートする方法

カラムの値で昇順もしくは降順に並び替えたい場合がよくあります。

WPFのDataGridコントロールではこの並べ替えの機能が備わっているのに対して、ListViewコントロールでは備わっていません。ListViewコントロールでデータをソートして表示するためには、CollectionViewSourceのソート機能を使います。

CollectionViewSourceのソート機能を使うことで、元のデータはソートしないまま、表示のみソートを行うことができます。先ほどのサンプルコードのTestクラス、TestListクラスはそのままで、MainWindow.xamlとMainWindow.xaml.csに変更を加えます。

このサンプルコードでは、XAMLファイルでクラスのインスタンス化を行います。Window.ResourcesタグでTestListクラスをオブジェクト名testlistでインスタンス化し、これをStaticResourceを使って参照します。

また、CollectionViewSourceタグでソートの設定を行います。さらに、Data Templateタグでカラムヘッダーに追加するマーク(▲、▼)に関して設定を行います。

ListViewタグでGridViewColumnHeader.Clickプロパティを指定し、CollectionViewSourceタグへバインディングしています。

MainWindow.xaml(一部のみ):

<Window>
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
</Window>

<Window.Resources>
        <local:TestList x:Key="testlist" />
        <CollectionViewSource x:Key="myView" Source="{Binding Source={StaticResource testlist}, Path=Data}" >
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Points"/>
                <scm:SortDescription PropertyName="Name"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
        <DataTemplate x:Key="HeaderTemplateArrowUp">
            <DockPanel>
                <TextBlock HorizontalAlignment="Center" Text="{Binding}"/>
                <Path x:Name="arrow"
                    StrokeThickness = "1" Fill = "gray"
                    Data = "M 6,12 L 14,12 L 10,4 L 6,12"/>
            </DockPanel>
        </DataTemplate>
        <DataTemplate x:Key="HeaderTemplateArrowDown">
            <DockPanel>
                <TextBlock HorizontalAlignment="Center" Text="{Binding}"/>
                <Path x:Name="arrow"
                      StrokeThickness = "1" Fill = "gray"
                      Data = "M 6,4 L 10,12 L 14,4 L 6,4"/>
            </DockPanel>
        </DataTemplate>
</Window.Resources>

<ListView ItemsSource="{Binding Source={StaticResource myView}}" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler"  x:Name="listView" >

MainWindow.xaml.csでGridViewColumnHeaderClickedHandlerイベントを定義します。

MainWindow.xaml.cs:

public partial class MainWindow : Window {

        // ListViewに関連付けられたCollectionViewSource
        private ICollectionView viewSource;

        // クリックされたヘッダーの情報を保持
        private GridViewColumnHeader lastHeaderClicked = null;

        // ソート方向(昇順、降順)の情報を保持
        private ListSortDirection lastDirection = ListSortDirection.Ascending;

        public MainWindow() {
            InitializeComponent();

            viewSource = (ICollectionView)listView.ItemsSource;
        }

        private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e) {

            // クリックされたカラムヘッダーの情報を取得
            GridViewColumnHeader clickedHeader = e.OriginalSource as GridViewColumnHeader;
            if (clickedHeader == null)
                return;
            if (clickedHeader.Role != GridViewColumnHeaderRole.Padding) {
                ListSortDirection direction = ListSortDirection.Ascending;
                if (clickedHeader == lastHeaderClicked
                    && lastDirection == ListSortDirection.Ascending) {
                    direction = ListSortDirection.Descending;
                }

                string header = (clickedHeader.Column.DisplayMemberBinding as Binding).Path.Path;

                // 並べ替えを実行
                Sort(header, direction);

                // カラムヘッダーのマーク(▲、▼)の変更
                if (direction == ListSortDirection.Ascending) {
                    clickedHeader.Column.HeaderTemplate = (DataTemplate)Resources["HeaderTemplateArrowUp"];
                } else {
                    clickedHeader.Column.HeaderTemplate = (DataTemplate)Resources["HeaderTemplateArrowDown"];
                }
                if (lastHeaderClicked != null && lastHeaderClicked != clickedHeader) {
                    lastHeaderClicked.Column.HeaderTemplate = null;
                }


                lastHeaderClicked = clickedHeader;
                lastDirection = direction;

            }

        }

        // 表示のソート処理
        private void Sort(string sortBy, ListSortDirection direction) {
            SortDescription sd = new SortDescription(sortBy, direction);
            viewSource.SortDescriptions.Clear();
            viewSource.SortDescriptions.Add(sd);
            viewSource.Refresh();
        }
}

実行結果:
c#_listview04

今回ご紹介した並べ替えの方法についてはこちらのサイトを参考にしています。

https://code.msdn.microsoft.com/windowsdesktop/WPF-ac0fb021

まとめ

ここではListViewコントロールについて説明しました。ListViewコントロールは表形式のデータを手軽に表示することができます。

使いこなすことができるように、この記事を何度も参考にして下さいね!

この記事を書いた人

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
info@sss-lab.com

目次