V4 V5

組込のセル型に日付ピッカーはありません。作り方を通して、 独自のセル型がホストの UI とどう連携するかを示します。

作るもの — 日付を表示し、右端のカレンダーボタンを押すと ホスト側の日付選択ダイアログが開くセル型です。

方針は 2 段構えです。

  • セル型(コア側) — 日付の描画とボタンの当たり判定。UI に依存しない
  • ホスト側CellButtonClicked を受けてダイアログを出し、値を書き戻す

コアは UI を持たないため、カレンダーそのものはコア側では出せません。 セル型は「押された」ことだけを伝え、実際のダイアログはホストが出します。

セル型を実装する

using unvell.ReoGrid.Core;
using unvell.ReoGrid.Core.CellTypes;
using unvell.ReoGrid.Core.Style;

/// <summary>日付を表示し、右端のカレンダーボタンでホストに日付選択を依頼するセル型。</summary>
public sealed class DatePickerCellType : CellTypeDescriptor
{
	private const double ButtonWidth = 18;
	private const uint Accent = 0xFF2D8CF0;      // 組込セル型と同じ水色
	private const uint HoverTint = 0xFFEAF4FE;

	private readonly string _format;

	public DatePickerCellType(string format = "yyyy/MM/dd") => _format = format;

	public override string TypeName => "datepicker";

	// 日付の文字列は自分で描く
	public override bool ReplacesText => true;

	// キーボードからの直接入力も許す(Excel の日付セルと同じ感覚)
	public override bool AllowsTextEditing => true;

	public override bool Paint(in CellTypePaintContext ctx)
	{
		// 値は Excel と同じシリアル値。0 は「未入力」として空欄にする
		double serial = ctx.Value.AsNumber;
		string text = serial > 0
			? DateTime.FromOADate(serial).ToString(_format)
			: "";

		var style = ctx.MakeTextStyle(HAlign.Left, VAlign.Middle);
		ctx.Graphics.DrawText(text, ctx.X + 3, ctx.Y, ctx.Width - ButtonWidth - 6, ctx.Height,
			ctx.TextColor, style);

		// 右端にカレンダーのボタンを描く(ホバー中は背景を付ける)
		double bx = ctx.X + ctx.Width - ButtonWidth;
		if (ctx.HoverRegion == 1)
			ctx.Graphics.FillRectangle(bx, ctx.Y + 1, ButtonWidth, ctx.Height - 2, HoverTint);

		// 枠だけの四角 = 外側を塗って内側を地色で抜く
		double gy = ctx.Y + ctx.Height / 2 - 5;
		ctx.Graphics.FillRectangle(bx + 4, gy, 10, 10, Accent);
		ctx.Graphics.FillRectangle(bx + 5, gy + 3, 8, 6, 0xFFFFFFFF);

		return true;
	}

	// ボタンの上だけをホバー領域 1 にする(それ以外は 0)
	public override int HitRegion(double localX, double localY, double width, double height)
		=> localX >= width - ButtonWidth ? 1 : 0;

	public override CellTypeClickResult OnClick(in CellTypeClickContext ctx)
		=> ctx.LocalX >= ctx.Width - ButtonWidth
			? CellTypeClickResult.RaiseButton()   // ホストの CellButtonClicked へ
			: CellTypeClickResult.Unhandled;

	public override void WriteConfig(IDictionary<string, object?> config)
		=> config["format"] = _format;
}

要点は 4 つです。

メンバー役割
Paintセルの中身を描く。true を返すと既定の描画は行われない
HitRegionホバー中の領域番号を返す。Paintctx.HoverRegion として渡る
OnClickクリックの結果を返す。RaiseButton()CellButtonClicked が上がる
WriteConfigreogrid-json に保存する設定値

AllowsTextEditingtrue にしているので、ボタンを使わずキーボードから 直接日付を打ち込むこともできます。ReplacesTexttrue なので、 セルの文字は既定の描画ではなく Paint が描いたものになります。

描画に使えるのは FillRectangle / DrawLine / DrawText / FillEllipse などの 基本的な図形だけです。プラットフォーム非依存にするための制約で、 組込のセル型も同じ範囲で描かれています(独自の描画層)。

割り当てる

ws.SetCellType(RangePosition.Parse("C2:C100"), new DatePickerCellType());

// 値は日付のシリアル値。表示形式はセル型が持つのでスタイル側は不要
ws.SetNumber(1, 2, new DateTime(2026, 8, 19).ToOADate());

値は Excel と同じシリアル値(1899-12-30 からの日数)です。 DateTime.ToOADate() / DateTime.FromOADate() で変換します。

シリアル値で持つため、DATEDIFTODAY()-C2 のような数式がそのまま使えます。 文字列で持つとこれができません。

ホスト側でダイアログを出す

grid.CellButtonClicked += (s, e) =>
{
    var ws = grid.ActiveWorksheet;
    if (ws.GetCellType(e.Cell.Row, e.Cell.Col) is not DatePickerCellType) return;

    using var dlg = new DatePickerForm();     // 自前のダイアログ
    if (dlg.ShowDialog(this) != DialogResult.OK) return;

    ws.RecordCell("日付の選択", e.Cell.Row, e.Cell.Col,
        () => ws.SetNumber(e.Cell.Row, e.Cell.Col, dlg.Value.ToOADate()));
    grid.RefreshExternal();
};

CellButtonClicked はボタンセル型と共通のイベントです。複数の種類のボタンを 置いている場合は、上のように GetCellType で判別してください。

WinForms なら MonthCalendar、WPF なら DatePicker を載せた小さなウィンドウで十分です。

履歴に載せる

// ホスト側: CellButtonClicked を受けて日付選択ダイアログを出し、結果を書き戻す
ws.RecordCell("日付の選択", row, col, () => ws.SetNumber(row, col, picked.ToOADate()));

RecordCell で包むと Ctrl+Z で戻せるようになります。包まずに SetNumber を 呼んだ場合、値は変わりますが履歴には載りません (元に戻す・やり直す)。

保存できるようにする

reogrid-json から読み戻せるようにするには、型名を登録します。

// reogrid-json から復元できるようにする
CellTypeRegistry.Register("datepicker",
	config => new DatePickerCellType(config.GetString("format") ?? "yyyy/MM/dd"));

WriteConfig で書き出した値が config として渡ってきます。 登録はアプリの起動時に一度行ってください。登録していないと、 読み込んだシートのそのセルはセル型なしになります。

別のやり方 — ドロップダウンで済ませる

選べる日付が限られている場合(例: 締め日の候補)は、セル型を作らずに DropdownCellType で十分です。

ws.SetCellType(1, 2, new DropdownCellType(["2026-08-31", "2026-09-30", "2026-10-31"]));

OnActivate から CellTypeClickResult.OpenDropdown(options) を返せば、 独自のセル型からドロップダウンを開くこともできます。ポップアップの表示は コントロールが行うため、ホスト側のコードは要りません。

次に読む

ページの内容は役に立ちましたか?