りおんクロニクル


SQLite × WPF DataGrid入門|一覧表示・編集・保存まで徹底解説【2026年版】

Home【2026年版】C# / .NET入門と実践ガイド|基礎・業務アプリ開発・SQLite連携まで体系的に解説

WPFで業務アプリを作るとき、SQLiteのデータをDataGridに表示したいというニーズは非常に多いです。 この記事では、SQLite → WPF DataGrid の最速パターンと、 編集内容をDBに保存する実務レベルの構成をまとめています。

この記事でわかること
・SQLiteのデータをWPF DataGridに表示する方法
・DataTable版 / ObservableCollection版の2パターン
・編集内容をSQLiteに反映する方法
・MVVMでのバインディング構成
・業務アプリ向けベストプラクティス

1. 前提:使用ライブラリとテーブル構成

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;
        }
    }
}

ポイント

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);
            }
        }
    }
}

ポイント

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. 業務アプリでのベストプラクティス

まとめ:SQLite × WPF DataGrid は業務アプリの定番構成

WPFで業務アプリを作るなら、 SQLite × DataGrid は最も現実的でコスパの良い組み合わせです。 この記事をベースに、自分のプロジェクトに合わせてカスタマイズしてみてください。

前のページ  次のページ