はじめに
前回の記事を多くの方に読んでいただけているようでうれしいです。
この記事で参考にした資料はページ最下部の参考リンクに記載しています。
今回は前回の続きで、そのBlazor HybridベースのWPFで「Excel操作を試してみた」という内容です。具体的には次の2つのライブラリを利用します する予定でした 。
- ClosedXML:Excelなしでも使える、軽量で高速なExcel操作ライブラリ
- Excel Interop:Excelアプリを直接操作できる、Microsoft公式API
Excel Interopの方だと、ここで紹介されている解決方法を試したものの、うまくいかなかったので諦めました。
結論だけ知りたいよ~という方のためにまとめると、WPF + Blazor Hybrid でもClosesXMLでExcel操作可能でした!
プロジェクト構成と環境
前回の記事で使った超シンプルな構成を進化させていきます![]()
/root
┣ /bin : ビルド成果物
┣ /obj
┣ /wwwroot : Blazor側の静的ファイル(CSS, JS, 画像など)を配置
┣ App.xaml : WPFのエントリポイント
┣ MainWindow.xaml : WPF側のメインウィンドウ
┣ BlazorWpfApp.csproj : プロジェクトファイル(依存関係やビルド設定を記述)
┣ BlazorWpfApp.sln : ソリューションファイル(複数プロジェクトの管理)
┗ Counter.razor : Blazorコンポーネント
- 環境
- Windows 11
- Visual Studio Code
- .NET 9 / WPF + Blazor Hybrid
- ClosedXML
ひとまずrazorコンポーネントからエクセルファイル作成処理を実行できるようにしてみます。
ClosedXMLでExcelを操作する
NuGetでClosedXMLをインストールします。
dotnet add package ClosedXML
Excelファイルを作成するクラス
ルートディレクトリにHelpersフォルダを作って次のクラスを格納します。ClosedXMLを使えるかどうかを確かめるだけなので鬼適当に書きます。
using ClosedXML.Excel;
public static class ExcelHelper
{
public static void CreateFile(string filePath)
{
using var wb = new XLWorkbook();
var ws = wb.Worksheets.Add("Sheet1");
ws.Cell("A1").Value = "名前";
ws.Cell("B1").Value = "点数";
ws.Cell("A2").Value = "田中";
ws.Cell("B2").Value = 90;
ws.Cell("A3").Value = "佐藤";
ws.Cell("B3").Value = 85;
wb.SaveAs(filePath);
}
}
コンポーネントの分割
プロジェクトのルートにComponentsフォルダを作って、前回使ったCounter.razorを格納します。
次にエクセル操作のコンポーネントを用意してComponentsフォルダに入れておきます。
@using BlazorWpfApp.Helpers
@using System.IO
<div class="card shadow-sm">
<div class="card-header bg-success text-white">
<h4 class="mb-0">Excel Export Demo</h4>
</div>
<div class="card-body">
<div class="mb-3">
<button class="btn btn-success btn-lg" @onclick="CreateExcelFiles">
<i class="bi bi-file-earmark-excel"></i> Export files
</button>
</div>
@if (!string.IsNullOrEmpty(message))
{
<div class="alert alert-info mt-3" style="white-space: pre-line">@message</div>
}
</div>
</div>
@code {
private string? message;
private void CreateExcelFiles()
{
try
{
var baseDir = Environment.CurrentDirectory;
var closedXmlPath = Path.Combine(baseDir, "sample_closedxml.xlsx");
// 両方の出力を実行
ExcelHelper.ExportWithClosedXml(closedXmlPath);
message = $"✅ Excelファイルを出力しました!\n" +
$"- ClosedXML: {closedXmlPath}";
}
catch (Exception ex)
{
message = $"❌ 出力に失敗しました: {ex.Message}";
}
}
}
この状態でプロジェクトのルートにBlazorのエントリーポイントを用意します。
@page "/counter"
@using BlazorWpfApp.Components;
<div class="container py-4">
<div class="mb-4">
<Counter />
</div>
<div>
<Excel />
</div>
</div>
MainWindow.xamlのRootComponentも次のようにしておきます。
<blazor:RootComponent Selector="#app" ComponentType="{x:Type local:Main}"/>
最終的なフォルダ構成は以下の通りです。
/root
┣ /bin : ビルド成果物
┣ /obj
┣ /wwwroot : Blazor側の静的ファイル(CSS, JS, 画像など)を配置
┣ /Components : メインから参照する細かいコンポーネント
┣ App.xaml : WPFのエントリポイント
┣ MainWindow.xaml : WPF側のメインウィンドウ
┣ BlazorWpfApp.csproj : プロジェクトファイル(依存関係やビルド設定を記述)
┣ BlazorWpfApp.sln : ソリューションファイル(複数プロジェクトの管理)
┗ Main.razor
動作確認
この状態でエクセルファイルの出力が可能か確認します。dotnet runコマンドを実行しすると、↓のように画面表示されました ![]()
また、出力されたエクセルのファイルも下記のようにデータが記入されていました。
まとめ
- Blazor Hybrid + WPFでClosedXMLを使ってExcel操作できる
- 細かい部分は未検証
- Excel Interopでも、もしかしたら動かせるのかもしれませんが、今回はビルドの壁を越えられませんでした
とはいえ、VSCode + WPF + Blazor Hybridでここまでできるようになったのは大きな進化です。「WPFの堅牢さ × BlazorのモダンUI × ClosedXMLの手軽さ」で新しい開発方法が見えてきた感があります。
今回調べきれなかった点は次の通りです。
- URLベースのページ遷移(例:
/homeから/aboutの遷移) - DIコンテナの利用可否
- コードベースでの試験実装
次回予告
次回は単体・結合・E2E試験を xUnit, Playwright辺りで実装できるか確かめます。

