V4 V5

The history is held per worksheet, by ws.Actions (an ActionManager).

Using it

using unvell.ReoGrid.Core;

if (ws.Actions.CanUndo) ws.Actions.Undo();
if (ws.Actions.CanRedo) ws.Actions.Redo();

Console.WriteLine(ws.Actions.UndoName);   // name of the operation undo would reverse
Console.WriteLine(ws.Actions.RedoName);

With a control, control.Undo() / control.Redo() / control.CanUndo / control.CanRedo call the same thing. Ctrl+Z and Ctrl+Y are wired up by default.

Getting an edit into the history

Core mutations do not depend on the history. Wrap the operation you want recorded in a recorder.

// wrapping an ordinary mutation is all it takes to get it into the history
ws.RecordCell("Enter value", 0, 0, () => ws.SetNumber(0, 0, 100));

ws.RecordRange("Apply format", RangePosition.Parse("A1:C10"), () =>
{
	for (int r = 0; r < 10; r++)
		ws.SetNumberFormat(r, 0, "#,##0");
});
RecorderCovers
RecordCell(name, row, col, mutate)One cell
RecordRange(name, rect, mutate, parts)A range
RecordAxis(name, target, rows, cols, mutate)Row and column metadata
RecordEdit(name, target, spec, mutate)The general form, for naming the target precisely

Calling ws.SetNumber(...) directly, without wrapping, changes the value but does not record it. Everything done through a control is wrapped internally, so edits made from the UI are recorded for you.

What gets captured

The history is a journal: it takes a snapshot before and after the operation and records the difference.

Captured — cells (values, styles, number formats, rich text, formulas), borders, merges, cell types, conditional formats, and row and column metadata.

Capture is sparse, so the cost is proportional to the range you edited. The sheet is never walked from end to end.

Insert and delete

Inserting and deleting rows and columns is handled specially.

  • Insert — undone by the inverse operation (a delete)
  • Delete — the band being removed is captured, clamped to the used range, and restored on undo; every formula is then swept to heal #REF!

Grouping several operations

An operation that is internally two steps — cut then paste — is combined into an ActionGroup and becomes one step. To the user, a single Ctrl+Z reverses both.

Capacity and events

ws.Actions.Capacity = 200;      // 100 by default
ws.Actions.Clear();

ws.Actions.Changed += () => Console.WriteLine("history changed");

bool hasHistory = ws.HasActions;   // answers without creating an ActionManager

Beyond the capacity, the oldest entries are dropped.

ws.HasActions answers without creating an ActionManager. On a headless sheet that has never been edited, the manager is never built.

The control reports the same thing through its HistoryChanged event. Use it to enable and disable toolbar buttons.

What is not recorded

  • Outlines (grouping and ungrouping)
  • Loading a file (the whole workbook is replaced)
  • View operations (zoom, freeze, scrolling)

Per sheet

The history is per worksheet. Switching sheets switches which history is in play.

Was this article helpful?