WPFで業務アプリを作るとき、SQLiteのデータをDataGridに表示したいというニーズは非常に多いです。 この記事では、SQLite → WPF DataGrid の最速パターンと、 編集内容をDBに保存する実務レベルの構成をまとめています。
この記事でわかること
・SQLiteのデータをWPF DataGridに表示する方法
・DataTable版 / ObservableCollection版の2パターン
・編集内容をSQLiteに反映する方法
・MVVMでのバインディング構成
・業務アプリ向けベストプラクティス
・SQLiteのデータをWPF DataGridに表示する方法
・DataTable版 / ObservableCollection版の2パターン
・編集内容をSQLiteに反映する方法
・MVVMでのバインディング構成
・業務アプリ向けベストプラクティス
1. 前提:使用ライブラリとテーブル構成
- DB:SQLite(sample.db)
- テーブル:Users(Id, Name, Age)
- ライブラリ:Microsoft.Data.Sqlite
Usersテーブル例
CREATE TABLE Users (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Age INTEGER
);
2. 最速パターン:DataTable → DataGridに表示
まずは「とにかく一覧表示したい」場合の最短コードです。
Window.xaml
<Window x:Class="SampleApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SQLite × WPF DataGrid" Height="450" Width="800">
<Grid>
<DataGrid x:Name="UsersGrid"
AutoGenerateColumns="True"
IsReadOnly="False"
Margin="10" />
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Data.Sqlite;
using System.Data;
using System.Windows;
namespace SampleApp
{
public partial class MainWindow : Window
{
private readonly string _cs = "Data Source=sample.db";
private DataTable _table;
public MainWindow()
{
InitializeComponent();
LoadData();
}
private void LoadData()
{
_table = new DataTable();
using var con = new SqliteConnection(_cs);
con.Open();
using var cmd = new SqliteCommand("SELECT * FROM Users", con);
using var reader = cmd.ExecuteReader();
_table.Load(reader);
UsersGrid.ItemsSource = _table.DefaultView;
}
}
}
ポイント
- DataTable.Load(reader) で一発読み込み
- WPFでは
DataGrid.ItemsSource = DataTable.DefaultView - AutoGenerateColumns=True で列自動生成
3. MVVM向け:ObservableCollectionでバインドする
業務アプリでは、ObservableCollection<User> を使う構成が扱いやすいです。
モデルクラス
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int? Age { get; set; }
}
ViewModelクラス
using Microsoft.Data.Sqlite;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class UsersViewModel : INotifyPropertyChanged
{
private readonly string _cs = "Data Source=sample.db";
public ObservableCollection<User> Users { get; } = new();
public event PropertyChangedEventHandler PropertyChanged;
public UsersViewModel()
{
Load();
}
private void OnPropertyChanged([CallerMemberName] string name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
public void Load()
{
Users.Clear();
using var con = new SqliteConnection(_cs);
con.Open();
using var cmd = new SqliteCommand("SELECT Id, Name, Age FROM Users", con);
using var reader = cmd.ExecuteReader();
while (reader.Read())
{
Users.Add(new User
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Age = reader.IsDBNull(2) ? (int?)null : reader.GetInt32(2)
});
}
}
public void Save(User user)
{
using var con = new SqliteConnection(_cs);
con.Open();
var sql = "UPDATE Users SET Name = @name, Age = @age WHERE Id = @id";
using var cmd = new SqliteCommand(sql, con);
cmd.Parameters.AddWithValue("@name", user.Name);
cmd.Parameters.AddWithValue("@age", (object?)user.Age ?? DBNull.Value);
cmd.Parameters.AddWithValue("@id", user.Id);
cmd.ExecuteNonQuery();
}
}
Window.xaml(MVVMバインド)
<Window x:Class="SampleApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SampleApp"
Title="SQLite × WPF DataGrid" Height="450" Width="800">
<Window.DataContext>
<local:UsersViewModel />
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Users}"
AutoGenerateColumns="False"
Margin="10"
IsReadOnly="False"
RowEditEnding="DataGrid_RowEditEnding">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Id}" IsReadOnly="True" />
<DataGridTextColumn Header="名前" Binding="{Binding Name}" />
<DataGridTextColumn Header="年齢" Binding="{Binding Age}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainWindow.xaml.cs(編集保存)
using System.Windows;
using System.Windows.Controls;
namespace SampleApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
if (e.EditAction != DataGridEditAction.Commit) return;
if (DataContext is UsersViewModel vm && e.Row.Item is User user)
{
vm.Save(user);
}
}
}
}
ポイント
- DataGridは
ItemsSource="{Binding Users}" - RowEditEnding で編集終了時にDBへ保存
- Id列は読み取り専用にしておくと安全
4. 新規追加行をDBにINSERTする
新規行も保存したい場合、Idが0のときはINSERTに切り替えます。
ViewModel.Save を拡張
public void Save(User user)
{
using var con = new SqliteConnection(_cs);
con.Open();
if (user.Id == 0)
{
var insert = "INSERT INTO Users (Name, Age) VALUES (@name, @age); " +
"SELECT last_insert_rowid();";
using var cmd = new SqliteCommand(insert, con);
cmd.Parameters.AddWithValue("@name", user.Name);
cmd.Parameters.AddWithValue("@age", (object?)user.Age ?? DBNull.Value);
var newId = (long)cmd.ExecuteScalar();
user.Id = (int)newId;
}
else
{
var update = "UPDATE Users SET Name = @name, Age = @age WHERE Id = @id";
using var cmd = new SqliteCommand(update, con);
cmd.Parameters.AddWithValue("@name", user.Name);
cmd.Parameters.AddWithValue("@age", (object?)user.Age ?? DBNull.Value);
cmd.Parameters.AddWithValue("@id", user.Id);
cmd.ExecuteNonQuery();
}
}
5. 削除ボタン付きDataGridにする
XAMLにボタン列を追加
<DataGridTemplateColumn Header="削除">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="削除"
Padding="4,2"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
CommandParameter="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
ViewModelにDeleteCommandを追加
using System.Windows.Input;
public ICommand DeleteCommand { get; }
public UsersViewModel()
{
DeleteCommand = new RelayCommand<User>(Delete);
Load();
}
private void Delete(User user)
{
if (user == null) return;
using var con = new SqliteConnection(_cs);
con.Open();
var sql = "DELETE FROM Users WHERE Id = @id";
using var cmd = new SqliteCommand(sql, con);
cmd.Parameters.AddWithValue("@id", user.Id);
cmd.ExecuteNonQuery();
Users.Remove(user);
}
簡易RelayCommand
public class RelayCommand<T> : ICommand
{
private readonly Action<T> _execute;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<T> execute)
{
_execute = execute;
}
public bool CanExecute(object parameter) => true;
public void Execute(object parameter)
{
if (parameter is T t)
_execute(t);
}
}
6. 業務アプリでのベストプラクティス
- 一覧表示だけなら DataTable + DefaultView が最速
- MVVMなら ObservableCollection + ViewModel で構成
- 編集保存は RowEditEnding or コマンドで制御
- Id列は読み取り専用にして壊れにくくする
- 大量データはページング(LIMIT / OFFSET)を検討
まとめ:SQLite × WPF DataGrid は業務アプリの定番構成
- DataTable版:とにかく早く動かしたいときに最適
- ObservableCollection版:MVVM・保守性重視の構成
- 編集・追加・削除まで一気通貫で実装できる
WPFで業務アプリを作るなら、 SQLite × DataGrid は最も現実的でコスパの良い組み合わせです。 この記事をベースに、自分のプロジェクトに合わせてカスタマイズしてみてください。