Banded rows are not a style. Nothing is written to a cell or a row: the sheet holds one
RowBanding, and the stripe is resolved during rendering, for visible cells only.
That is why striping a million rows costs one object, and why it survives sorting, filtering and row insertion untouched.
The basics
using unvell.ReoGrid.Core;
using unvell.ReoGrid.Core.Style;
// tint every other row of the sheet — one object, whatever the row count
ws.Banding = RowBanding.Every(0xFFF2F7FBu);
// and off again
ws.Banding = null;
RowBanding.Every(color) is shorthand for “tint every other row of the sheet with color”.
It leaves FirstColor unset, so only one side of the alternation is painted and the rest keeps
the sheet’s own background.
Range and stripe size
// skip the header row and paint two-row bands in two colors
ws.Banding = new RowBanding
{
Range = RangePosition.Parse("A2:F1000"),
FirstColor = 0xFFFFFFFFu,
SecondColor = 0xFFEFF4F9u,
StripeSize = 2,
};
| Property | Default | What it does |
|---|---|---|
Range | null (whole sheet) | The rows and columns the stripes cover. Row 0 of the range is the first stripe, so starting below a header row leaves the header alone |
FirstColor | null | Fill for the first band (ARGB); null leaves those rows unpainted |
SecondColor | null | Fill for the second band (ARGB); null leaves those rows unpainted |
StripeSize | 1 | Rows per band; 1 is the classic every-other-row stripe |
Mode | VisibleRow | Whether hidden rows count when numbering the stripes |
Hidden rows
// the default: hidden rows are not counted, so filtering never leaves two stripes adjacent
var banding = new RowBanding
{
SecondColor = 0xFFEFF4F9u,
Mode = BandingMode.VisibleRow,
};
ws.Banding = banding;
// pin the stripe to the row number instead (hidden rows still count)
ws.Banding = banding with { Mode = BandingMode.PhysicalRow };
VisibleRow(default) — counts only the rows on screen. When a filter removes rows the stripes are renumbered, so two same-colored rows never end up adjacent.PhysicalRow— counts by row number, pinning a stripe to its row.
VisibleRow counts through AxisIndex.HiddenCountBefore (a sorted array with binary search,
cached by version), so scrolling through 500,000 rows triggers no scan.
The fill order
Strongest first; the first one that applies wins.
- A fill from conditional formatting
- The cell’s own fill — a background set on the cell, its row or its column
- The stripe
The second point matters: it asks the style chain, not the inherited effective style. Every effective style carries the root’s white, so testing that would make “has a background” true for every cell on the sheet. Asking the chain is what lets a cell painted white on purpose break the pattern.
bool striped = ws.HasBanding;
// the fill a row actually gets, or null when the band leaves it alone
uint? fill = ws.BandFillFor(3, 0);
// whether the cell, its row or its column sets a background of its own.
// If one does, the stripe leaves that cell alone
bool own = ws.HasOwnBackground(3, 0);
_ = (striped, fill, own);
Row and column edits
A band follows the data it stripes. Inserting or deleting rows shifts Range with them, and
a band whose rows are all deleted disappears with them (Banding returns to null).
In the controls
All three controls expose SetRowBanding(RowBanding?). Pass null to clear.
I/O
- reogrid-json — saved as the sheet’s
banding(a V5 extension). Default values are omitted, so a sheet with no striping still serializes byte-identically to reogrid-web. - XLSX — not supported. Excel keeps striping inside a table style rather than as a
sheet property, so round-tripping it belongs with the table feature (
StripeSizeis the seam they will share). Exporting to XLSX loses the stripes.
Try it in Studio
Format ▸ Alternating Rows ▸ Stripe the Whole Sheet / Stripe the Selection /
Stripe the Selection… (pick a color) / None.