C#でDataGridに表示するデータを操作してみた
WPFのDataGridにバインディングするコレクションを操作して、DataGridの表示を操作してみました。
目次
環境
- Visual Studio 2015 Express for Windows Desktop 
処理の流れ
DataGridやListViewにコレクションをバインドする場合ですが、ObservableCollectionクラスのコレクションにすると便利です。ObservableCollectionのインスタンスに登録したデータを変更すると、バインドしたコントロールに変更通知が送られて、コントロールの表示も変更されるからです。
- 基になるデータをデータベースからDataTableやCollectionに読み込む。 
- レコードに含まれるフィールドを定義したクラスを作る。 
- 定義したクラスの型のObservableCollectionクラスのインスタンスを作る。 
- ObservableCollectionクラスのインスタンスを、表示用のコントロール(DataGridやListView)にバインドする。 
- LINQを使ってDataTableやCollectionから抽出や結合したデータを定義したレコードクラスのインスタンスにして、ObservableCollectionのインスタンスに追加する。 
 
何というか、言葉ではわかりにくいですね。試してみましょう。
試してみた
System.Data.SQLiteを使ってSQLite3のデータを表示するアプリを作ってみます。データベースには2つのテーブル(短歌テーブルと歌人テーブル)があり、それぞれのテーブルの内容と2つのテーブルを結合した結果を表示します。表示の内容は、ボタンによって切り替えます。
XAML
XAMLは下記にしました。
<Window x:Class="datagrid_trial.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:datagrid_trial"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="200">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="80" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="50" />
            <RowDefinition Height="50" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <DataGrid Name="datagrid" ItemsSource="{Binding}" Grid.Column="0" Grid.Row="0" Grid.RowSpan="4"
                  AlternationCount="2"
                  AlternatingRowBackground="AliceBlue"
                  GridLinesVisibility="Vertical"
                  VerticalGridLinesBrush="LightGray"
                  CanUserAddRows="False"
                  CanUserDeleteRows="False" SelectionUnit="Cell"/>
        <Button Name="buttonPoem" Content="短歌" Grid.Column="1" Grid.Row="0" Margin="5" Click="buttonPoem_Click" />
        <Button Name="buttonPoet" Content="歌人" Grid.Column="1" Grid.Row="1" Margin="5" Click="buttonPoet_Click" />
        <Button Name="buttonMarge" Content="短歌と歌人" Grid.Column="1" Grid.Row="2" Margin="5" Click="buttonMarge_Click" />
    </Grid>
</Window>
DataGrid要素に ItemsSource=”{Binding}”として、バインドしたものを表示するように設定します。
コード部
コードは下記の様にしました。
using System;
using System.Linq;
using System.Windows;
using System.Data;
using System.Data.Common;
using System.Collections.ObjectModel;
namespace datagrid_trial
{
    public partial class MainWindow : Window
    {
        // データを保持するDataTableの作成
        DataTable poemTable = new DataTable();
        DataTable poetTable = new DataTable();
        ObservableCollection<ViewData> ViewCollection = new ObservableCollection<ViewData>();
        public class ViewData
        {
            public string Field1 { get; set; }
            public string Field2 { get; set; }
            public string Field3 { get; set; }
        }
        public MainWindow()
        {
            InitializeComponent();
            ReadDataFromDatabaseToDataTable();
            datagrid.DataContext = ViewCollection;
        }
        private void ReadDataFromDatabaseToDataTable()
        {
            // データの読み込み
            try
            {
                DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SQLite");
                using (DbConnection connection = factory.CreateConnection())
                {
                    connection.ConnectionString = "Data Source=poemData.db"; // ファイル名を指定する
                    using (connection)
                    {
                        // コマンドを作る
                        DbCommand command = connection.CreateCommand();
                        command.CommandText = "SELECT * FROM poem";
                        command.CommandType = CommandType.Text;
                        command.Connection = connection;
                        // DataAdapterを作る
                        DbDataAdapter adapter = factory.CreateDataAdapter();
                        adapter.SelectCommand = command;
                        // 読み込み
                        adapter.Fill(poemTable);
                        // コマンドを作る
                        DbCommand command2 = connection.CreateCommand();
                        command2.CommandText = "SELECT * FROM poet_master";
                        command2.CommandType = CommandType.Text;
                        command2.Connection = connection;
                        // DataAdapterを作る
                        DbDataAdapter adapter2 = factory.CreateDataAdapter();
                        adapter2.SelectCommand = command2;
                        // 読み込み
                        adapter2.Fill(poetTable);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        private void buttonPoem_Click(object sender, RoutedEventArgs e)
        {
            ViewCollection.Clear();
            var query = from r in poemTable.AsEnumerable() select r;
            foreach (var r in query)
            {
                ViewData v = new ViewData();
                v.Field1 = r.Field<Int64>("id").ToString();
                v.Field2 = r.Field<string>("body");
                v.Field3 = r.Field<Int64>("poet").ToString();
                ViewCollection.Add(v);
            }
            datagrid.Columns[0].Header = "ID";
            datagrid.Columns[1].Header = "短歌";
            datagrid.Columns[2].Header = "詠み人ID";
        }
        private void buttonPoet_Click(object sender, RoutedEventArgs e)
        {
            ViewCollection.Clear();
            var query = from r in poetTable.AsEnumerable() select r;
            foreach(var r in query)
            {
                ViewData v = new ViewData();
                v.Field1 = r.Field<Int64>("id").ToString();
                v.Field2 = r.Field<string>("name");
                ViewCollection.Add(v);
            }
            datagrid.Columns[0].Header = "ID";
            datagrid.Columns[1].Header = "歌人";
            datagrid.Columns[2].Header = "";
        }
        private void buttonMarge_Click(object sender, RoutedEventArgs e)
        {
            ViewCollection.Clear();
            // 結合を実行する
            var query =
                from p in poemTable.AsEnumerable()
                join q in poetTable.AsEnumerable()
                on p.Field<Int64>("poet") equals q.Field<Int64>("id")
                select new
                {
                    body = p.Field<string>("body"),
                    poet = q.Field<string>("name")
                };
            foreach (var s in query)
            {
                ViewData v = new ViewData();
                v.Field1 = s.body;
                v.Field2 = s.poet;
                ViewCollection.Add(v);
            }
            datagrid.Columns[0].Header = "短歌";
            datagrid.Columns[1].Header = "歌人";
            datagrid.Columns[2].Header = "";
        }
    }
}
部分毎に解説します。
まず、コードには現れませんが、最初にNuGetでSystem.Data.SQLiteパッケージを追加しておきます。
using System;
using System.Linq;
using System.Windows;
using System.Data;
using System.Data.Common;
using System.Collections.ObjectModel;
using System.Dataとusing System.Data.Commonは、ADO.Net(DbProviderFactory)でデータを読み込むためのものです。System.Collections.ObjectModelはObservableCollectionクラスを使用するためのものです。
private void ReadDataFromDatabaseToDataTable()
{
    // 中略
}
このメソッドでデータベースからデータをDataTableに読み込みます。
DataTable poemTable = new DataTable();
DataTable poetTable = new DataTable();
ObservableCollection<ViewData> ViewCollection = new ObservableCollection<ViewData>();
public class ViewData
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
    public string Field3 { get; set; }
}
ViewDataというクラスは、ObservableCollectionに入れるデータの型を表すクラスです。
ObservableCollection<ViewData> ViewCollection = new ObservableCollection<ViewData>()でViewData型のObservableCollectionのインスタンス(ViewCollection)を作ります。
このViewCollectionをDataGridにバインドすると、ViewDataクラスの各プロパティがDataGridのカラムになります。
private void buttonMarge_Click(object sender, RoutedEventArgs e)
{
    ViewCollection.Clear();
    // 結合を実行する
    var query =
        from p in poemTable.AsEnumerable()
        join q in poetTable.AsEnumerable()
        on p.Field<Int64>("poet") equals q.Field<Int64>("id")
        select new
        {
            body = p.Field<string>("body"),
            poet = q.Field<string>("name")
        };
    foreach (var s in query)
    {
        ViewData v = new ViewData();
        v.Field1 = s.body;
        v.Field2 = s.poet;
        ViewCollection.Add(v);
    }
    datagrid.Columns[0].Header = "短歌";
    datagrid.Columns[1].Header = "歌人";
    datagrid.Columns[2].Header = "";
}
ボタンをクリックしたときの処理は似てますので、1つだけ説明します。上記のボタンでは、2つのDataTableを結合した結果をObservableCollectionに入れています。最初にViewCollection.Clear()で既存のObservableCollectionインスタンス内のデータを全部削除します。queryにLINQのクエリを設定してforeachでLINQクエリを実行します。foreach内でViewDataクラスのインスタンスを作ってObservableCollectionインスタンスにAddします。
DataGrid.Columnsは、DataGridのカラムの情報のコレクションです。このコレクションの各要素にHeaderプロパティがあって、そのHeaderプロパティに文字列を代入すると、そのカラムの列タイトルになります。
「DataGridにバインドしたObservableCollectionインスタンスをClearした後にLINQの結果をAddする」という処理を、各ボタンのコードに書くわけです。
動かしてみた
使用したデータ
SQLite3データベース内の2つのテーブルの内容は下記にしました。
poemテーブルの中身は下記です。
| id | body | poet | 
|---|---|---|
| 1 | あかねさす紫野行き標野行き野守は見ずや君が袖振る | 2 | 
| 2 | あしひきの山川の瀬の鳴るなへに弓月が岳に雲立ち渡る | 1 | 
| 3 | うらうらに照れる春日にひばり上がり心悲しも独し思へば | 15 | 
| 4 | うらさぶる心さまねしひさかたの天のしぐれの流らふ見れば | 18 | 
| 5 | たまきはる宇智の大野に馬並めて朝踏ますらむその草深野 | 17 | 
| 6 | ぬばたまの夜の更けゆけば久木生ふる清き川原に千鳥しば鳴く | 9 | 
| 7 | ひさかたの天の香具山この夕霞たなびく春立つらしも | 1 | 
| 8 | み吉野の象山の際の木末にはここだも騒く鳥の声かも | 9 | 
| 9 | わたつみの豊旗雲に入り日差し今夜の月夜清く照りこそ | 19 | 
| 10 | 葦辺行く鴨の羽交ひに霜降りて寒き夕は大和し思ほゆ | 11 | 
poet_masterテーブルの中身は下記です。
| id | name | 
|---|---|
| 1 | 柿本人麻呂 | 
| 2 | 額田王 | 
| 3 | 笠女郎 | 
| 4 | 狭野弟上娘子 | 
| 5 | 遣唐使の母 | 
| 6 | 高市黒人 | 
| 7 | 作者不明 | 
| 8 | 山上憶良 | 
| 9 | 山部赤人 | 
| 10 | 市原王 | 
| 11 | 志貴皇子 | 
| 12 | 持統天皇 | 
| 13 | 大津皇子 | 
| 14 | 大伯皇女 | 
| 15 | 大伴家持 | 
| 16 | 大伴旅人 | 
| 17 | 中皇命 | 
| 18 | 長田王 | 
| 19 | 天智天皇 | 
| 20 | 天武天皇 | 
| 21 | 東歌 | 
| 22 | 湯原王 | 
| 23 | 藤原鎌足 | 
| 24 | 磐姫皇后 | 
| 25 | 舒明天皇 | 
poemテーブルのpoetフィールドとpoet_masterテーブルのidがリレーションします。
動かしてみた
ビルドして実行すると下図のようになります。各ボタンを押した状態です。
 
 
 
ObservableCollectionインスタンスの中身を変えるだけで表示が変わりました。
公開日
広告
C#でデータ処理カテゴリの投稿
- C#でDataAdapterを使ってAccessのデータベースを読み書きしてみた
- C#でDataAdapterを使ってAccessのデータベースを読み書きしてみた(OleDb編)
- C#でDataGridに表示するデータを操作してみた
- C#でDataTableのカラムのデータ型を読んでみた
- C#でDataTableの自動インクリメントをしてみた
- C#でJSON形式のデータを出力してみた
- C#でLinq to objectの結果をDataTableにしてみた
- C#でSQLite3のデータベースを使ってみる(ADO.NET ファクトリーデザインパターン)
- C#でSQLiteを使ってみる(インストール)
- C#でコレクションの要素の数を調べる
- C#でコレクションを内部結合してみた
- C#でコレクションを左外部結合してみた
- C#でコレクションを昇順または降順に並び替える
- C#で渡された配列を加工して配列で返す関数について注意すること
- C#のキューを試してみた
- C#のスタックを試してみた