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#のスタックを試してみた