🎯 この記事の目的
この記事では、WPF + SQLite + CommunityToolkit.Mvvm を使って
「名前と年齢を登録し、DataGridで一覧表示するアプリ」を
最小構成で実装する方法を紹介します。
💡 完成イメージ
- 名前と年齢を入力して「登録」ボタンを押すとSQLiteに保存されます
- 下のDataGridに保存済みのデータが一覧表示されます
- MVVM構成 + DI対応(Microsoft.Extensions.DependencyInjection)
🧱 プロジェクト構成
WpfMinimalMvvm/
│ App.xaml
│ App.xaml.cs
│ MainWindow.xaml
│ MainWindow.xaml.cs
├─ Models/
│ └── Employee.cs
├─ IServices/
│ └── IEmployeeRepository.cs
├─ Services/
│ ├── SqliteEmployeeRepository.cs
│ ├── IWindowService.cs
│ └── WindowService.cs
└─ ViewModels/
└── MainViewModel.cs
🧩 WpfMinimalMvvm.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<UseWPF>true</UseWPF>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
</ItemGroup>
</Project>
🧩 App.xaml / App.xaml.cs
<Application x:Class="WpfMinimalMvvm.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
using Microsoft.Extensions.DependencyInjection;
using System.Windows;
using WpfMinimalMvvm.IServices;
using WpfMinimalMvvm.Services;
using WpfMinimalMvvm.ViewModels;
namespace WpfMinimalMvvm
{
public partial class App : Application
{
private ServiceProvider? _provider;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var services = new ServiceCollection();
services.AddSingleton<IEmployeeRepository, SqliteEmployeeRepository>();
services.AddSingleton<IWindowService, WindowService>();
services.AddTransient<MainViewModel>();
services.AddTransient<MainWindow>();
_provider = services.BuildServiceProvider();
var window = _provider.GetRequiredService<MainWindow>();
window.Show();
}
}
}
🧩 Models/Employee.cs
namespace WpfMinimalMvvm.Models
{
public class Employee
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
public bool IsActive { get; set; }
}
}
🧩 IServices/IEmployeeRepository.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using WpfMinimalMvvm.Models;
namespace WpfMinimalMvvm.IServices
{
public interface IEmployeeRepository
{
Task<int> InsertAsync(Employee employee);
Task<List<Employee>> GetAllAsync();
}
}
🧩 Services/SqliteEmployeeRepository.cs
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Threading.Tasks;
using WpfMinimalMvvm.IServices;
using WpfMinimalMvvm.Models;
namespace WpfMinimalMvvm.Services
{
using System.Data.SQLite;
using System.IO;
using WpfMinimalMvvm.IServices;
using WpfMinimalMvvm.Models;
namespace WpfMinimalMvvm.Services
{
public class SqliteEmployeeRepository : IEmployeeRepository
{
private readonly string _dbPath;
public SqliteEmployeeRepository()
{
_dbPath = Path.Combine(Directory.GetCurrentDirectory(), "app.db");
// 初回のみテーブル作成
using (var cn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
{
cn.Open();
using (var cmd = cn.CreateCommand())
{
cmd.CommandText = @"
CREATE TABLE IF NOT EXISTS Employees(
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Age INTEGER NOT NULL,
IsActive INTEGER NOT NULL
);";
cmd.ExecuteNonQuery();
}
}
}
public async Task<int> InsertAsync(Employee employee)
{
if (string.IsNullOrWhiteSpace(employee.Name))
{
throw new ArgumentException("Name は必須です。");
}
using (var cn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
{
await cn.OpenAsync();
using (var cmd = cn.CreateCommand())
{
cmd.CommandText = @"
INSERT INTO Employees (Name, Age, IsActive)
VALUES (@name, @age, @active);
SELECT last_insert_rowid();
";
cmd.Parameters.AddWithValue("@name", employee.Name);
cmd.Parameters.AddWithValue("@age", employee.Age);
cmd.Parameters.AddWithValue("@active", employee.IsActive ? 1 : 0);
var idObj = await cmd.ExecuteScalarAsync();
return Convert.ToInt32(idObj);
}
}
}
public async Task<List<Employee>> GetAllAsync()
{
var list = new List<Employee>();
using (var cn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
{
await cn.OpenAsync();
using (var cmd = cn.CreateCommand())
{
cmd.CommandText = @"SELECT Id, Name, Age, IsActive FROM Employees ORDER BY Id;";
using (var rd = await cmd.ExecuteReaderAsync())
{
while (await rd.ReadAsync())
{
var e = new Employee
{
Id = rd.GetInt32(0),
Name = rd.GetString(1),
Age = rd.GetInt32(2),
IsActive = rd.GetInt32(3) == 1
};
list.Add(e);
}
}
}
}
return list;
}
}
}
🧩 MainWindow.xaml
<Window x:Class="WpfMinimalMvvm.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SQLite Insert Sample" Height="480" Width="700">
<DockPanel Margin="12">
<TextBlock DockPanel.Dock="Top"
Text="{Binding Status}" Margin="0,0,0,8" />
<StackPanel DockPanel.Dock="Top"
Orientation="Horizontal"
Margin="0,0,0,8">
<StackPanel Width="200">
<TextBlock Text="Name" />
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<StackPanel Width="100" Margin="12,0,0,0">
<TextBlock Text="Age" />
<TextBox Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<CheckBox Content="Is Active"
IsChecked="{Binding IsActive}"
VerticalAlignment="Bottom"
Margin="12,0,0,0" />
<Button Content="登録"
Command="{Binding SaveCommand}"
Width="100" Height="32"
Margin="12,0,0,0"
VerticalAlignment="Bottom" />
</StackPanel>
<DataGrid ItemsSource="{Binding Items}"
AutoGenerateColumns="True"
IsReadOnly="True" />
<StatusBar DockPanel.Dock="Bottom" Margin="0,8,0,0">
<TextBlock Text="{Binding Message}" />
</StatusBar>
</DockPanel>
</Window>
🧩 MainWindow.xaml.cs
using System.Windows;
using WpfMinimalMvvm.ViewModels;
namespace WpfMinimalMvvm
{
public partial class MainWindow : Window
{
public MainWindow(MainViewModel vm)
{
InitializeComponent();
DataContext = vm;
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
if (DataContext is MainViewModel vm)
{
vm.LoadCommand.Execute(null);
}
}
}
}
✅ 動作手順
- この構成のままビルド・実行
- 「Name」「Age」を入力して「登録」
- DataGrid に一覧表示されます
-
app.dbが自動生成され、SQLiteでデータが永続化されます
🚀 まとめ
このサンプルは 最小のMVVM + DI + SQLite構成 です。
拡張する場合は以下のような機能を追加できます:
- 更新・削除処理の追加
- SubWindowを
IWindowService経由で開く - 検索やフィルタリング機能
- 非同期処理中のプログレス表示
💬 コメント・LGTM歓迎です!