DataGridViewの表データを、エクセルファイルに変換するプログラムを作成しました。
デモプロジェクト
2022/09/16追記:列の並び替えにも対応しました
使用ライブラリ
C#からエクセルファイルを出力するライブラリです。
ClosedXmlと比較して、3倍~8倍速いです。(100行程度の場合。10万行だと圧倒的な差がでます。)
ただし凝った装飾などは指定できません。(数値書式、日付書式のカスタマイズは可能)
ですので、お手軽にダンプ出力したい用途に向いています。
コード
DumpExcelHelper.cs の拡張メソッドとしてToExcelFileが定義されています。
呼び出し方は以下になります。
dataGridView1.ToExcelFile(saveFileDialog1.FileName);
DumpExcelHelper 処理内容
DataGridViewのDataGridViewRowの値を
シリアライズするクラスを用意します。
タイトル行生成とシリアライズの処理を記述します。
public void WriteTitle(ref ExcelSerializerWriter writer, DataGridViewRow value, ExcelSerializerOptions options, string name)
{
var serializer = options.GetRequiredSerializer<string>();
var cells = value.Cells.OfType<DataGridViewCell>()
.OrderBy(c => c.OwningColumn.DisplayIndex);
foreach (var cell in cells)
{
serializer.Serialize(ref writer, cell.OwningColumn.HeaderText, options);
}
}
public void Serialize(ref ExcelSerializerWriter writer, DataGridViewRow value, ExcelSerializerOptions options)
{
var serializer = options.GetRequiredSerializer<object>();
var cells = value.Cells.OfType<DataGridViewCell>()
.OrderBy(c => c.OwningColumn.DisplayIndex);
foreach (var cell in cells)
{
serializer.Serialize(ref writer, cell.Value, options);
}
}
クラスをプロバイダに登録します。
readonly IExcelSerializerProvider _dataGridViewExcelProvider
= ExcelSerializerProvider.Create(
new[] { new DataGridViewExcelSerializer() },
new[] { ExcelSerializerProvider.Default });
準備が整ったのでメインの出力処理です。
シリアライザの設定クラスを用意して、ToFileメソッドを呼ぶとファイルが作成されます。
(フォルダ作成・削除の権限が必要です。内部で作業フォルダとファイルのZIP圧縮を行うため)
なお、今回はエクセルの1行目にタイトル行を表示したいのでHeaderTextを抽出します。
var newConfig = ExcelSerializerOptions.Default with
{
Provider = _dataGridViewExcelProvider,
CultureInfo = CultureInfo.CurrentCulture,
HasHeaderRecord = hasHeaderRecord,
HeaderTitles = headerTitles ?? Array.Empty<string>(),
AutoFitColumns = autoFitColumns,
NumberFormat = "#,##0.000;[Red]\\-#,##0.000",
};
ExcelSerializer.ToFile(value, fileName, newConfig);
C#側のデータ型に応じて、エクセルのほうも文字、数値、日付に対応します。
例えば、文字列型の場合は、エクセルでも文字扱いになりますので、前0があっても安心です。
(付録)DataGridViewのデータ取得処理の概要
foreach (var row in dataGridView1.Rows.Cast<DataGridViewRow>())
{
foreach (var c in row.Cells.OfType<DataGridViewCell>())
{
Debug.Write($"{c.Value},");
}
Debug.WriteLine("");
}
シリアライザについて
IEnumerableから型に応じた値を取得する処理は
CysharpさんのWebSerializerの方式を使用しています。
拡張性もあり高速に動作する素晴らしい設計です。