The sheet-wide state lives in SheetProtection (ws.Protection). Protection has the same two layers as Excel. Every cell is locked by default, and that
lock only bites once the sheet is protected. So building an input form goes: unlock the
ranges people should fill in, then protect the sheet.
The basic shape
using unvell.ReoGrid.Core;
using unvell.ReoGrid.Core.Protection;
// every cell is locked by default, so open the ones meant for input first
ws.SetRangeLock(RangePosition.Parse("B2:B100"), LockState.Unlocked);
// only now does the lock bite
ws.Protect();
// with a password (it guards Unprotect and nothing else — see the note below)
ws.Protect("template");
Lock states live in a range-scoped side table (ProtectionTable), so unlocking a whole
column is one entry and writes nothing to any cell. Opening a column of a million rows costs
the same as opening one cell.
Lookups subtract rectangles newest-first, which means the most recent setting wins and no per-cell loop is ever needed.
The permission flags
// what stays permitted while protection is on (Excel's "Protect Sheet" checkboxes)
ws.Protection.AllowSort = true;
ws.Protection.AllowAutoFilter = true;
ws.Protection.AllowFormatCells = true;
// forbid selection itself (both default to true, meaning selection is allowed)
ws.Protection.AllowSelectLockedCells = false;
ws.Protect();
| Property | Default | What it permits while protection is on |
|---|---|---|
AllowSelectLockedCells | true | Selecting locked cells |
AllowSelectUnlockedCells | true | Selecting unlocked cells |
AllowFormatCells | false | Changing cell formatting |
AllowFormatRows / AllowFormatColumns | false | Changing row heights and column widths |
AllowInsertRows / AllowInsertColumns | false | Inserting rows and columns |
AllowDeleteRows / AllowDeleteColumns | false | Deleting rows and columns |
AllowSort | false | Sorting |
AllowAutoFilter | false | Using the auto-filter |
Note that the two selection flags default the other way round. OOXML states these as
prohibitions (insertRows="1" means “inserting rows is blocked”) while V5 states them as
permissions, so every flag is inverted on the way in and out. The selection pair starts out
“not prohibited”, which inverts to true. Getting this backwards silently produces a sheet
nobody can click on.
Asking about the state
bool on = ws.IsProtected;
// whether the cell is marked locked (answered even while protection is off)
bool locked = ws.IsCellLocked(1, 1);
// whether it can actually be edited right now: unprotected, or not locked
bool editable = ws.IsCellEditable(1, 1);
// a whole range, answered with rectangle arithmetic rather than a per-cell loop
bool rangeOk = ws.IsRangeEditable(RangePosition.Parse("B2:B100"));
_ = (on, locked, editable, rangeOk);
IsCellLocked reports the lock marking itself and answers even while protection is off.
To know whether a cell can be edited right now, use IsCellEditable.
Catching a refusal
ws.EditRefused += (_, e) =>
{
// e.Reason is Cells / Axis / Structure
// e.Message carries the same wording Excel uses
_ = $"{e.Reason}: {e.Message} ({e.Range?.ToAddress()})";
// set Handled once you have explained it yourself; the control then skips its own alert
e.Handled = true;
};
ProtectionRefusedEventArgs.Reason (a ProtectionRefusal) has three values.
| Value | What was refused |
|---|---|
Cells | The target cells are locked |
Axis | Formatting rows or columns is not permitted |
Structure | Inserting or deleting rows or columns is not permitted |
Message carries the same wording Excel uses. Set Handled once you have explained it
yourself and the control skips its own alert. The edit is refused either way — protection
is not negotiable from here. WinForms and WPF show a message box; Avalonia has no standard
modal, so it draws a bubble inside the grid.
Lifting it
// a wrong password returns false and leaves the sheet protected
bool ok = ws.Unprotect("template");
_ = ok;
// drop the lock overrides themselves (independent of the protection switch)
ws.LockStates.Clear();
What protection actually stops
User actions, and only those. The chokepoints are the paths that go through the edit
recorder, plus the RequestEdit call a control makes before opening an editor. The model
API stays open, so a file loader or your own host code can still write to a protected sheet.
That is the same line Excel draws with UserInterfaceOnly.
About the password
The password on Protect(password) is Excel’s 16-bit verifier
(<sheetProtection password="…">). It is not encryption — collisions are trivial to produce,
and Excel treats it accordingly.
V5 does no more with it than guard Unprotect. Do not use it to withhold data: anyone who
can open the file can read the cells. It exists so a workbook authored in Excel round-trips
looking the way it was authored.
Undo and I/O
- Changes to lock states are captured in the sheet snapshot.
- reogrid-json — saved as the sheet’s
protection.enabledand the rangeoverridesmatch reogrid-web;passwordandalloware V5 extensions. - XLSX — read and written as
<sheetProtection>. The per-cell locks live in the cell format in OOXML (<xf><protection locked="0"/>), so they travel through the styles and are folded back into the range table on load.
Try it in Studio
Review ▸ Protect Sheet… / Unprotect Sheet…, and Review ▸ Lock Cells / Unlock Cells.