A control raises seven events. The names and arguments are the same on WinForms, WPF and Avalonia.

EventRaised whenTypically used for
SelectionChangedThe selection or active cell changedUpdating a formula bar or status bar
WorkbookChangedThe workbook was replacedRebuilding sheet tabs
ActiveSheetChangedThe displayed sheet changedThe sheet tab’s selected state
HistoryChangedThe history changedEnabling and disabling Undo / Redo
ZoomChangedThe zoom factor changedUpdating a zoom indicator
ContextMenuRequestedA right-click happenedBuilding the menu
CellButtonClickedA button cell type was pressedRunning your business logic

The samples below are written against the Avalonia build; swapping the using makes them work verbatim on the WinForms and WPF builds.

The selection changed

using unvell.ReoGrid.Avalonia;
using unvell.ReoGrid.Core;

grid.SelectionChanged += (_, _) =>
{
	CellPosition active = grid.ActiveCell;
	RangePosition range = grid.Selection;
	Console.WriteLine($"active {active.Row},{active.Col} / selection {range.Rows}×{range.Cols}");
};

When building your own formula bar, re-read grid.GetActiveCellInput() from this event (Cell Editing).

Arrow-key movement, mouse dragging and a call to MoveTo() all raise the same event — there is no way to tell “the user did it” from “the code did it”. When you need that distinction, raise a flag around your own calls.

The workbook or sheet changed

// when the whole workbook is replaced (NewWorkbook / LoadWorkbook / LoadJson)
grid.WorkbookChanged += (_, _) => Console.WriteLine($"sheets {grid.Workbook.Count} ");

// when the displayed sheet changes
grid.ActiveSheetChanged += (_, _) => Console.WriteLine(grid.ActiveWorksheet.Name);

Building your own sheet tabs means handling both: rebuild the tabs on WorkbookChanged and sync the selected one on ActiveSheetChanged.

There is no built-in sheet tab UI. If you want tabs, lay out grid.Workbook.Worksheets yourself and call grid.SetWorksheet(ws).

History and zoom

// keep the toolbar's Undo and Redo buttons in step
grid.HistoryChanged += (_, _) =>
{
	Console.WriteLine($"Undo={grid.CanUndo} Redo={grid.CanRedo}");
};

grid.ZoomChanged += (_, _) => Console.WriteLine($"{grid.Zoom:P0}");

ZoomChanged also fires for Ctrl+wheel (Zoom).

Right-click

There is no built-in context menu. A right-click only raises ContextMenuRequested, and the host builds the menu — how a menu is constructed differs per platform, so the core cannot supply one.

grid.ContextMenuRequested += (_, e) =>
{
	switch (e.Target)
	{
		case GridContextTarget.Cell:         /* the menu for a cell */ break;
		case GridContextTarget.RowHeader:    /* for a row header; e.Index is the row */ break;
		case GridContextTarget.ColumnHeader: /* for a column header; e.Index is the column */ break;
		case GridContextTarget.Corner:       /* the select-all button in the corner */ break;
	}
};
GridContextMenuEventArgsWhat it is
TargetCell / RowHeader / ColumnHeader / Corner
CellThe active cell after the click
IndexThe row or column index, for a header
ScreenLocationWhere to show the menu

A right-click settles the selection before raising the event. Right-clicking inside the selection keeps it; right-clicking outside collapses it to one cell (as in Excel).

A button cell type was pressed

grid.CellButtonClicked += (_, e) =>
    Console.WriteLine($"{e.Cell.Row},{e.Cell.Col}");

Checkboxes, dropdowns and hyperlinks are handled by the control, so they raise no event (Cell Type Basics).

Knowing that a cell value changed

There is no cell-value-changed event. Worksheet is a UI-independent model, used for things like writing hundreds of thousands of cells on a server, so it does not raise an event per write.

There are two approaches instead.

// there is no cell-value-changed event; catch your own writes where you make them
void SetChecked(int row, bool value)
{
	ws.RecordCell("Check", row, 0, () => ws.SetBoolean(row, 0, value));
	OnCellChanged(row, 0);
}

// edits made through the UI land in the history, so catch them here
ws.Actions.Changed += () => Console.WriteLine("the sheet was edited");

SetChecked(0, true);
  • Changes your own code makes — call your handler where you make them
  • Edits by the user — catch ws.Actions.Changed (the same source the control’s HistoryChanged comes from). It only tells you that something changed, not which cell

When you do need the specific cell, the practical approach is to remember the edit position from SelectionChanged and re-read it when HistoryChanged fires.

Was this article helpful?