DataGridView:数値・日付・通貨の表示書式を設定する
📋 目次(クリックで展開)
- 結論:DefaultCellStyle.Format の設定例
- Format が効く条件
- 値が IFormattable であること
- ValueType を確認する
- 自動生成列では設定タイミングに注意
- 書式指定子の一覧
- 数値
- カスタム数値書式
- 日付・時刻
- スタイルの優先順位
- null と空欄の扱い
- NullValue:表示を差し替える
- DataSourceNullValue:書き戻す値を決める
- カルチャを指定する
- Format は配置を変えない
- CellFormatting を使うべきケース
- 実装例
- パフォーマンスに注意
- 落とし穴
- 桁区切りを設定すると編集で例外が出る
- ソートは元の値で行われる
- クリップボードには書式後の値が載る
- 列幅の自動調整は書式後の幅で計算される
- 指定方法の比較
- まとめ
- 関連記事
DataGridView に金額を表示したら 1000 とそのまま出てしまう。日付が 2026/08/10 0:00:00 になって時刻が邪魔——。
いずれも DefaultCellStyle.Format に書式指定子を渡すだけで解決します。ただし Format は「効く条件」があり、そこを外すと何も起こりません。また桁区切りを設定すると、編集時に例外が出るという副作用も潜んでいます。
この記事では、書式指定の基本から、Format が無視される原因、CellFormatting との使い分け、実務ではまる落とし穴までを整理します。
結論:DefaultCellStyle.Format の設定例
列単位で DefaultCellStyle.Format を設定します。
// 金額:3桁区切り、小数なしdataGridView1.Columns["Price"].DefaultCellStyle.Format = "N0";
// 通貨記号付きdataGridView1.Columns["Amount"].DefaultCellStyle.Format = "C0";
// 日付のみ(時刻を出さない)dataGridView1.Columns["OrderDate"].DefaultCellStyle.Format = "yyyy/MM/dd";
// パーセント(0.15 → 15%)dataGridView1.Columns["Rate"].DefaultCellStyle.Format = "P0";グリッド全体に一括で適用することもできます。
// 全セル共通の既定書式dataGridView1.DefaultCellStyle.Format = "N0";これで表示されない場合は、次章の「効く条件」を確認してください。
Format が効く条件
値が IFormattable であること
Format は内部的に value.ToString(format, formatProvider) を呼び出しています。つまり IFormattable を実装した型でなければ何も起こりません。
| 値の型 | Format | 理由 |
|---|---|---|
int / decimal / double |
効く | IFormattable 実装済み |
DateTime / DateTimeOffset |
効く | 同上 |
string |
効かない | IFormattable 未実装 |
bool |
効かない | 同上 |
| 独自クラス | 実装次第 | IFormattable を実装すれば効く |
「N0 を設定したのに桁区切りが出ない」というケースの大半は、値が文字列になっているためです。
ValueType を確認する
まず実際の型を確認してください。
foreach (DataGridViewColumn column in dataGridView1.Columns){ Debug.WriteLine($"{column.Name}: {column.ValueType?.Name}");}String と出た列は、書式指定の前にデータソース側の型を直す必要があります。
DataTable の場合は列定義で型を指定します。
var table = new DataTable();table.Columns.Add("Price", typeof(decimal)); // string にしないtable.Columns.Add("OrderDate", typeof(DateTime));SQL から読み込んだデータで型が崩れる場合は、SELECT 側のキャストか DataTable の再定義で対処します。
クラスをバインドしている場合はプロパティの型がそのまま反映されます。
public class Product{ public string Name { get; set; } public decimal Price { get; set; } // string にしない public DateTime OrderDate { get; set; } public decimal Rate { get; set; }}自動生成列では設定タイミングに注意
AutoGenerateColumns が true(既定)の場合、列は DataSource を設定した瞬間に生成されます。それより前に Columns["Price"] へアクセスすると例外になります。
// NG:列がまだ存在しないdataGridView1.Columns["Price"].DefaultCellStyle.Format = "N0";dataGridView1.DataSource = bindingSource1;
// OK:バインド後に設定するdataGridView1.DataSource = bindingSource1;dataGridView1.Columns["Price"].DefaultCellStyle.Format = "N0";DataBindingComplete イベントで設定する方法もありますが、このイベントは再バインドのたびに発火します。毎回スタイルを作り直さないよう、フラグで初回のみに絞るか、代入前に既存値を確認してください。
書式指定子の一覧
数値
decimal、int、double などに使用します。表示例は ja-JP 環境のものです。
| 指定子 | 意味 | 値 | 表示 |
|---|---|---|---|
N0 |
桁区切り・小数0桁 | 1234567 |
1,234,567 |
N2 |
桁区切り・小数2桁 | 1234.5 |
1,234.50 |
C0 |
通貨・小数0桁 | 1500 |
¥1,500 |
C2 |
通貨・小数2桁 | 1500 |
¥1,500.00 |
P0 |
パーセント | 0.15 |
15% |
P1 |
パーセント・小数1桁 | 0.155 |
15.5% |
F1 |
固定小数点 | 1234.56 |
1234.6 |
D5 |
整数・0埋め | 42 |
00042 |
X |
16進数 | 255 |
FF |
P 指定子は値を100倍します。 15 を渡すと 1,500% になります。データベースに 15 で保存している場合は、0.15 に変換するか N0 + CellFormatting で % を付与してください。
カスタム数値書式
標準指定子で表現できない場合はカスタム書式を使います。
| 書式 | 値 | 表示 |
|---|---|---|
#,##0 |
1234 |
1,234 |
#,##0.00 |
1234.5 |
1,234.50 |
#,### |
0 |
(空欄) |
#,##0 円 |
1500 |
1,500 円 |
#,##0;(#,##0) |
-500 |
(500) |
#,##0;▲#,##0;- |
-500 |
▲500 |
セミコロンで区切ると 正数・負数・ゼロ の3パターンを指定できます。会計系の画面で負数を ▲ 表示にする、ゼロをハイフンにするといった要件はこれで足ります。
# と 0 の違いは、値がないときに桁を表示するかどうかです。#,### は 0 を空欄にし、#,##0 は 0 と表示します。
日付・時刻
| 書式 | 表示例 |
|---|---|
yyyy/MM/dd |
2026/08/10 |
yyyy年M月d日 |
2026年8月10日 |
yyyy/MM/dd HH:mm |
2026/08/10 14:30 |
MM/dd (ddd) |
08/10 (月) |
HH:mm:ss |
14:30:00 |
d |
2026/08/10(短い日付・カルチャ依存) |
D |
2026年8月10日(長い日付・カルチャ依存) |
t |
14:30(短い時刻) |
大文字と小文字を混同しないでください。
| 誤りやすい組み合わせ | 正しい意味 |
|---|---|
MM / mm |
MM = 月、mm = 分 |
HH / hh |
HH = 24時間制、hh = 12時間制 |
dd / DD |
dd = 日、DD は無効 |
yyyy/mm/dd と書くと 2026/30/10 のような表示になります。分が月の位置に入るためです。
日付の入力側をカレンダーにしたい場合は、書式設定とは別に編集用コントロールの実装が必要です。
スタイルの優先順位
Format を設定したのに反映されない場合、別のスタイルに上書きされている可能性があります。
DataGridView のセルスタイルは6段階で継承され、下にあるものが優先されます。
| 優先 | 設定箇所 |
|---|---|
| 1(最強) | DataGridViewCell.Style |
| 2 | DataGridViewRow.DefaultCellStyle |
| 3 | DataGridView.AlternatingRowsDefaultCellStyle(奇数行のみ) |
| 4 | DataGridView.RowsDefaultCellStyle |
| 5 | DataGridViewColumn.DefaultCellStyle |
| 6(最弱) | DataGridView.DefaultCellStyle |
重要なのは、プロパティ単位で継承される点です。上位でセル背景色だけを設定しても、Format は下位のものが引き継がれます。
// 列で書式を設定dataGridView1.Columns["Price"].DefaultCellStyle.Format = "N0";
// 行で背景色だけ設定 → Format は列の N0 が維持されるdataGridView1.Rows[0].DefaultCellStyle.BackColor = Color.LightYellow;
// 行で書式も設定 → こちらが勝つdataGridView1.Rows[0].DefaultCellStyle.Format = "C0";実際に適用されている値は InheritedStyle で確認できます。
var applied = dataGridView1.Rows[0].Cells["Price"].InheritedStyle;Debug.WriteLine($"適用中の Format: {applied.Format}");デバッグ時にはこれが最も速い切り分け手段です。
null と空欄の扱い
NullValue:表示を差し替える
値が null または DBNull のとき、代わりに表示する内容を指定します。
// 未入力を「未定」と表示するdataGridView1.Columns["OrderDate"].DefaultCellStyle.NullValue = "未定";
// ハイフンで埋めるdataGridView1.Columns["Price"].DefaultCellStyle.NullValue = "-";NullValue は Format より優先されます。値が null の時点で書式適用は行われません。
なお DataGridViewImageColumn では NullValue の既定値がエラーアイコンになっており、画像が未設定のセルに × マークが表示されます。
DataSourceNullValue:書き戻す値を決める
ユーザーがセルを空にしたとき、データソースへ何を書き込むかを指定します。既定は DBNull.Value です。
// クラスバインドで null を書き戻すdataGridView1.Columns["Note"].DefaultCellStyle.DataSourceNullValue = null;
// 空文字を書き戻すdataGridView1.Columns["Note"].DefaultCellStyle.DataSourceNullValue = string.Empty;DataTable バインドでは DBNull.Value のままで問題ありませんが、List<T> バインドで string プロパティに DBNull を代入しようとすると例外になります。この場合は null または string.Empty を明示してください。
| バインド先 | 推奨する DataSourceNullValue |
|---|---|
DataTable |
DBNull.Value(既定のまま) |
| クラスの参照型プロパティ | null |
クラスの Nullable<T> プロパティ |
null |
| クラスの非 null 値型 | 空欄を許容しない設計にする |
カルチャを指定する
FormatProvider を指定すると、カルチャ依存の表示を制御できます。
// 通貨記号をドルにするdataGridView1.Columns["UsdPrice"].DefaultCellStyle.Format = "C2";dataGridView1.Columns["UsdPrice"].DefaultCellStyle.FormatProvider = CultureInfo.GetCultureInfo("en-US");未指定の場合は CurrentCulture(実行環境の設定)が使われます。開発機と本番機でロケールが異なると表示が変わるため、通貨や日付を厳密に固定したい画面では明示するのが安全です。
InvariantCulture を使えば環境差をなくせますが、日本語環境では区切り文字が英語圏の形式になります。表示用途では避け、ファイル出力など機械可読なデータに使ってください。
Format は配置を変えない
数値に N0 を設定しても、右寄せにはなりません。配置は別プロパティです。
var style = dataGridView1.Columns["Price"].DefaultCellStyle;style.Format = "N0";style.Alignment = DataGridViewContentAlignment.MiddleRight;数値列が左寄せのままだと桁が揃わず、金額の比較がしづらくなります。書式設定とセットで行うのが実務上の定石です。
まとめて設定するヘルパーを用意しておくと楽になります。
private static void ApplyNumericStyle( DataGridViewColumn column, string format = "N0"){ var style = column.DefaultCellStyle; style.Format = format; style.Alignment = DataGridViewContentAlignment.MiddleRight;}CellFormatting を使うべきケース
Format は「値そのものの書式化」しかできません。次のような要件では CellFormatting イベントを使います。
| 要件 | 手段 |
|---|---|
| 固定の書式を適用する | Format |
| 条件によって書式を変える | CellFormatting |
| 他の列の値を参照する | CellFormatting |
| コード値を名称に変換する | CellFormatting |
| 値の範囲で色を変える | CellFormatting |
実装例
private void DataGridView1_CellFormatting( object sender, DataGridViewCellFormattingEventArgs e){ if (dataGridView1.Columns[e.ColumnIndex].Name != "Status") { return; }
// コード値を表示用の名称に変換する e.Value = e.Value switch { 0 => "未処理", 1 => "処理中", 2 => "完了", _ => "不明", };
// これを忘れると Format が再適用される e.FormattingApplied = true;}e.FormattingApplied = true の設定を忘れないでください。 これを省くと、DataGridView は「まだ書式化されていない」と判断し、セルスタイルの Format を上から適用しようとします。結果として意図しない表示になります。
パフォーマンスに注意
CellFormatting は再描画のたびに、表示範囲の全セル分だけ発火します。スクロールすれば何百回も呼ばれます。
ここで DB アクセスや重い計算を行うと、スクロールが目に見えて重くなります。マスタの参照が必要なら、事前に Dictionary へ読み込んでおいてください。
private Dictionary<int, string> _statusNames;
private void LoadMaster(){ // 起動時に一度だけ読み込む _statusNames = statusRepository.GetAll() .ToDictionary(s => s.Code, s => s.Name);}
private void DataGridView1_CellFormatting( object sender, DataGridViewCellFormattingEventArgs e){ if (e.Value is int code && _statusNames.TryGetValue(code, out var name)) { e.Value = name; e.FormattingApplied = true; }}落とし穴
桁区切りを設定すると編集で例外が出る
最もはまりやすい問題です。
Format = "N0" を設定した列を編集モードにすると、テキストボックスには 1,234 とカンマ付きで表示されます。ユーザーがそのまま確定すると、DataGridView は 1,234 を int に変換しようとして失敗します。
System.FormatException: 'DataGridViewComboBoxCell の値が有効ではありません'または「入力文字列の形式が正しくありません。」対処は2通りあります。
A. CellParsing で自前解析する
private void DataGridView1_CellParsing( object sender, DataGridViewCellParsingEventArgs e){ if (dataGridView1.Columns[e.ColumnIndex].Name != "Price") { return; }
var text = e.Value as string;
if (string.IsNullOrWhiteSpace(text)) { e.Value = null; e.ParsingApplied = true; return; }
// カンマを許容して解析する if (decimal.TryParse( text, NumberStyles.Number | NumberStyles.AllowThousands, CultureInfo.CurrentCulture, out var value)) { e.Value = value; e.ParsingApplied = true; } // 解析できなければ ParsingApplied を立てず、既定処理と DataError に委ねる}NumberStyles.AllowThousands が要点です。これを指定しない decimal.Parse はカンマを受け付けません。
B. 編集時だけ書式を外す
private void DataGridView1_CellBeginEdit( object sender, DataGridViewCellCancelEventArgs e){ if (dataGridView1.Columns[e.ColumnIndex].Name == "Price") { dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] .Style.Format = string.Empty; }}
private void DataGridView1_CellEndEdit( object sender, DataGridViewCellEventArgs e){ if (dataGridView1.Columns[e.ColumnIndex].Name == "Price") { // セル個別のスタイルを解除して列の設定に戻す dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] .Style.Format = null; }}編集中は生の数値、確定後は書式付きという挙動になります。入力しやすさを優先するならこちらです。
ただしセル単位でスタイルを生成するため、大量行を編集する画面ではメモリ消費が増えます。行数が多い場合はAを選んでください。
ソートは元の値で行われる
Format は表示だけを変えるため、並べ替えは書式化前の値を基準に行われます。これは正しい挙動です。
1,000 と 900 を文字列比較すれば 1,000 が先に来ますが、数値比較なので 900 が先になります。書式に惑わされず期待どおりに並びます。
一方で CellFormatting でコード値を名称に変換した列は、名称ではなくコード順に並びます。ユーザーから見ると「あいうえお順になっていない」と映るため、名称順が必要ならデータソース側に表示名の列を持たせてください。
クリップボードには書式後の値が載る
Ctrl + C でコピーされるのは書式適用後の文字列です。N0 を設定した列は 1,234 としてコピーされます。
Excel に貼り付ける際は問題になりませんが、貼り付け先で再解析する場合はカンマの扱いに注意が必要です。
列幅の自動調整は書式後の幅で計算される
AutoSizeMode による自動調整は、書式適用後の表示文字列を基準にします。N0 で桁区切りを付けると文字数が増えるため、書式設定の後に列幅を調整してください。
dataGridView1.Columns["Price"].DefaultCellStyle.Format = "N0";dataGridView1.Columns["Price"].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;指定方法の比較
| 方法 | 適用範囲 | メモリ | 向いているケース |
|---|---|---|---|
DataGridView.DefaultCellStyle |
全セル | 小 | グリッド共通の既定値 |
Column.DefaultCellStyle |
列全体 | 小 | 通常はこれ |
Row.DefaultCellStyle |
行全体 | 中 | 合計行など特定行 |
Cell.Style |
単一セル | 大 | 例外的なセルのみ |
CellFormatting |
条件次第 | — | 動的な変換が必要な場合 |
列単位が基本です。セル単位のスタイルは行数に比例してオブジェクトが増えるため、ループで一括設定するのは避けてください。
// NG:行数ぶんスタイルオブジェクトが生成されるforeach (DataGridViewRow row in dataGridView1.Rows){ row.Cells["Price"].Style.Format = "N0";}
// OK:列に一度だけ設定するdataGridView1.Columns["Price"].DefaultCellStyle.Format = "N0";まとめ
- 書式は
DefaultCellStyle.Formatに指定子を渡すだけ。列単位での設定が基本 FormatはIFormattableな型にしか効かない。反映されないときはValueTypeがStringになっていないか確認する- 自動生成列では
DataSource設定後に書式を指定する P指定子は値を100倍する。15ではなく0.15を渡す- 日付の
MMは月、mmは分。HHは24時間制、hhは12時間制 - スタイルは6段階で継承され、プロパティ単位で上書きされる。
InheritedStyleで実際の適用値を確認できる NullValueは表示の差し替え、DataSourceNullValueは書き戻す値。役割が異なるFormatは配置を変えない。数値列はAlignmentで右寄せする- 桁区切りを設定すると編集時の再変換で失敗する。
CellParsingか編集時の書式解除で対処する - 条件付きの変換は
CellFormatting。e.FormattingApplied = trueを忘れない
関連記事
- DataGridView 条件付き書式の実装テクニック(サンプルあり)
- DataGridView:大量データでも重くならない条件付き書式とスクロール遅延対策(サンプルあり)
- DataGridView:ヘッダーとセルのフォント変更方法(サンプルあり)
- DataGridView:セル編集時の入力制限(サンプルあり)
- DataGridView:日付編集時にカレンダー(DateTimePicker)を利用する方法(サンプルあり)
- DataGridView に DataTable をバインドする(サンプルあり)
- DataGridView:Excel と相互コピー&ペーストする方法(サンプルあり)
💬 コメント