· @Jeffrey
Summary
A datasheet template opened and saved in the Kendo Spreadsheet editor must come back exactly as it went in, because every datasheet generated from it inherits its formatting. The Kendo Spreadsheet (2026.1.415) cannot hold everything an Excel workbook can, so the editor keeps the template intact in four ways:
- Server passes around Kendo. On load, a GemBox pass writes formatting Kendo would miss (column-level styles, the workbook default font, default row heights and column widths) onto the individual cells, rows and columns. On save, a second pass puts back border styles Kendo cannot draw (hair, dotted, dashed, double).
- Sidecars for what Kendo has no concept of. Text rotation travels beside the workbook as a list and is written back by GemBox on save.
- Display-only decoration. Field-cell colours and static-image previews are drawn on the rendered cells and never written into the template.
- Proof. A round-trip check reloads every stored template through Kendo and Save's own pipeline and diffs the result against the stored file with GemBox.
Status (7 October 2026): proven live. On the fourth run of the round-trip check, no template on PL00026 showed any difference caused by Kendo; what remains is by design (see Test results). The round-trip check, the K drive tests and the rotation, highlight and preview work are committed (447ffe48); the load and save passes are not committed yet.
How a template travels
Every template the Spreadsheet edits passes through a server pass on the way in and another on the way out; the browser never writes to storage itself.
The stored workbook leaves the bucket through the load pass and reaches Kendo with its formatting made explicit. Save sends Kendo's workbook back through the border restore, the field-token pass and the rotation pass before it is stored. Export runs the same passes plus the print settings and downloads instead of storing. The round-trip check runs load and save end to end and diffs the result instead of storing it.
What Kendo cannot hold, and what we do
Each row is a gap between an Excel workbook and the Kendo Spreadsheet, found by reading Kendo or by the round-trip check, with the safeguard that closes it.
Gap | What happens without a safeguard | Safeguard | Where |
|---|---|---|---|
Formatting set on a whole column ( | Cells formatted only through their column lose it: vertical centre, font size, wrap | Load pass writes each cell's resolved formatting onto the cell | Server, load |
Workbook default font (Normal style) | Cells with no font of their own become Arial 9 pt instead of, for example, Calibri 11 | Load pass gives those cells their own style; Kendo then reads the font | Server, load |
Default row height and column width ( | Rows without their own height take Kendo's default (10.5 pt rows became 14.25 pt) | Load pass makes every row height and column width explicit; save pass puts back each sheet's default row height, because Kendo's export writes its own | Server, load and save |
Border styles other than thin, medium, thick | Hair, dotted, dashed and double lines come back as thin, medium or thick | Save pass restores the stored style where Kendo returned its stand-in | Server, save and export |
Text rotation | Kendo has none: no import, display or export | Rotation list kept beside the workbook, drawn with CSS, written back by GemBox | Browser and server |
Field cells | A field is only its cell value | Colour drawn on the rendered cell, never saved; typing into a field cell is refused | Browser |
Static image fields | Kendo cannot show them | Picture drawn as the cell's CSS background, never saved | Browser |
Print setup (paper, orientation, margins, fit) | Kendo writes A4 defaults | Re-applied from the template's print settings on every load and export | Server |
Pictures already in the template | Round-trip natively as Kendo drawings | None needed | Kendo |
Font size display | Kendo stores pixels (8 pt = 10.67 px) | Toolbar shows and sets points | Browser |
Load-side preparation pass
The preparation pass rewrites the workbook the browser receives so Kendo reads every cell's real formatting; in Excel nothing visible changes. It runs only when the Spreadsheet editor loads a template; the stored file is not touched until someone saves.
For each sheet, over the area the round-trip check scans, and never less than Kendo's own sheet of 200 rows by 50 columns, because Kendo shows and saves all of it (the used range including formatted empty cells, plus every allocated row and column, capped at 600 by 600):
- Snapshot every cell's resolved formatting: its own style if it has one, otherwise its row or column style, otherwise the workbook default. Number format, alignment, wrap, rotation, indent, font, fill, borders and protection are copied value by value.
- Set the workbook's Normal style to Kendo's own default (Arial 9 pt). GemBox writes a cell whose style equals the workbook default without a style index, and Kendo treats a cell with no style index as Kendo-default. With the default changed, a cell whose real font was the old default is no longer default-styled, so it is written with its own index.
- Write each snapshot back onto its cell as an explicit style, then re-apply every drawn border side. GemBox treats an edge shared by two cells, or by two stacked merged ranges, as one line, so writing a later cell's style can wipe a line an earlier cell drew. The second pass puts every drawn side back; a drawn side always wins over an undrawn one.
- Make every row height and column width in the area explicit.
Why step 2 is needed was checked live on 7 October 2026: a cell carrying any style index, even index 0, keeps the workbook font through Kendo; only a cell with no index falls back to Arial 12 px. Changing Kendo's own default after the widget is built has no effect.
Side effect: the next save from the Spreadsheet stores these explicit styles and sizes. The file is larger, and TreeGrid and datasheet generation read it the same way.
Save-side border restore
When the Spreadsheet saves or exports, the server puts back a stored border style that Kendo could not represent, cell side by cell side, before the field-token pass and the rotation pass run. Kendo keeps only a line size, so it returns hair, dotted and dashed as thin, medium-dashed as medium, and double as thick.
A side of a cell is restored only when all of these hold:
- the stored template has a style Kendo cannot represent on that side;
- the saved workbook has one of Kendo's styles (thin, medium, thick) there, not none, so a border the user removed stays removed;
- both have the same colour, treating an unset colour as black because Kendo writes black explicitly;
- the cell's value is unchanged, and so is the value of the neighbouring cell across that edge, because GemBox treats a cell's edge and its neighbour's facing edge as one line.
If nothing qualifies, the saved bytes are returned untouched.
The rule cannot tell Kendo's conversion apart from a user who deliberately turned a hair border into thin; that border is restored to hair. To really change it, choose medium or thick, or remove the border and save, then add the new one.
Proof: the round-trip check
The round-trip check is the evidence for retiring TreeGrid: it shows, per template, everything a load and save through the Spreadsheet would change. It saves nothing.
How to run it. On Datasheet Templates (Spreadsheet), tick the templates to check (none ticked = all), then click the check-mark button Spreadsheet Round-Trip Check. Keep the browser window visible: in a hidden or fully covered window Chrome stops drawing and Kendo's file load never finishes, so the run sits on "Checking 1 of N".
What it does per template. The template is loaded exactly as the editor loads it (including the preparation pass) into a hidden Spreadsheet. The xlsx is rebuilt exactly as Save builds it and posted to a compare-only action. That action runs Save's server pipeline (border restore, field-token pass, rotations) and diffs the result against the stored file with GemBox.
What it compares. Cell values and formulas; font (name, size in points, bold, italic, underline, colour); fill; borders; alignment; wrap; rotation; number format; merged ranges; column widths (1.5 px tolerance); row heights (0.75 pt tolerance); hidden rows and columns; pictures; data validations; conditional formats; sheet names; frozen panes; print setup.
How to read it. Each template shows Identical, Differences (count) or Skipped (no workbook stored). Under it, each category lists its most frequent changes with only the attributes that changed and a count, for example "R: Hair → Thin × 333". Print setup differences are expected and harmless (see the table above). Static-field cells re-pointed to another connection's field of the same name come from Save's own token pass, which TreeGrid's save also runs.
First run, before the load and save passes (PL00026, 12 templates, 52 s).
Result | Templates | Main differences |
|---|---|---|
Identical | 2 | none: one had already been saved by the Spreadsheet, so a second pass changes nothing |
Skipped | 2 | empty templates |
Differences | 8 | about 11,000 hair borders as thin; 7,500 cells losing column-level centring and 1,080 a 9 pt column font; default font Calibri 11 as Arial 9; 101 rows 10.5 pt as 14.25 pt |
Second run, with the passes (11 templates). Three were identical and two skipped. The hair borders on 316 and 349 and the default font on 346 came back intact. Two bugs in the load pass showed up. It covered only the used area, so rows 100 to 200 of 316, column AN onward of 347 and row 72 of 371 to 373 still took Kendo's defaults. It also wiped 108 border sides between stacked merged ranges on 371 to 373. Both were fixed.
Third run (11 templates, 44 s). Every difference Kendo caused was gone except rows 100 to 200 of 316, still 10.5 pt → 14.25 pt. Kendo reads a sheet's default row height and keeps it, but its export writes its own default (19 px, 14.25 pt) and leaves the height off every row at the default it read. The rows without a height are exactly the rows at the stored default, so the save pass now puts the stored default back.
Test results
Fourth run of the round-trip check, 7 October 2026 at 14:51, on the rebuilt site. All 11 templates of PL00026 were checked in 42 s. Nothing was saved. The site log shows every comparison returned 200 and no errors.
Template | Id | Result | What differs, and why it is accepted |
|---|---|---|---|
Datasheet, INSTRUMENT, Temperature Indicator | 316 | Identical | Nothing (3 sheets, 50,800 cells) |
Date Datasheet | 346 | Identical | Nothing |
Index, INSTRUMENT, CONDUCTIVITY TRANSMITTER | 347 | 1 difference | The autofilter name |
Datasheet MECHANICAL Pump | 349 | 121 differences | 120 static-field cells re-pointed by name to this connection's static fields (Save's own token pass, which TreeGrid's save also runs; the template was copied from another connection), and print setup |
BlankCopyTest | 361 | Skipped | No workbook stored |
Datasheet Blank | 369 | Identical | Nothing |
Multivariable Transmitter Datasheet | 371 | 2 differences | Print setup on each of its 2 sheets |
Multivariable Transmitter DatasheetResaved | 372 | 2 differences | Print setup on each of its 2 sheets |
Multivariable Transmitter DatasheetTest1 | 373 | 2 differences | Print setup on each of its 2 sheets |
DatasheetTemplateNew | 423 | Skipped | No workbook stored |
Datasheet - Pumps - Pump | 424 | Identical | Nothing |
Print setup differs because Kendo writes A4 defaults. It is accepted because the template's own print settings are re-applied on every load and export, so it never reaches a generated datasheet.
The four gaps across the four runs. Counts are what the check reported on PL00026.
Gap | Run 1, no passes | Run 2 | Run 3 | Run 4 |
|---|---|---|---|---|
Hair borders returned as thin | 10,884 cell sides (316, 349) | 0 | 0 | 0 |
Column-level styles dropped | about 8,600 cell differences in alignment, font size and wrap (316, 347, 349) | 1,034 cell differences (347, column AN onward) | 0 | 0 |
Workbook default font replaced | 346, 369, 371 to 373 | 90 cells (371 to 373, row 72) | 0 | 0 |
Default row height replaced | 101 rows (316) | 101 rows (316) | 101 rows (316) | 0 |
Borders lost between stacked merged ranges (caused by the first load pass) | none | 324 sides (108 on each of 371 to 373) | 0 | 0 |
Unit tests, run on the same code. DatasheetTemplateFidelityTests and DatasheetTemplateRoundTripTests are part of 87 datasheet tests: 86 pass and 1 is skipped. The skipped one is the opt-in test that runs the load pass on a real stored template. Run against each of the 9 non-empty templates on PL00026, it passed every time. With the fix for the merged-range loss switched off, it fails on 371 to 373 with exactly the 108 sides the live run showed.
Scope of the proof. One connection, 9 non-empty templates. Run the check on other connections before TreeGrid is retired; any new difference it shows is either a gap not yet seen or one of the accepted items above.
Unit tests. DatasheetTemplateFidelityTests (22) cover the comparison itself. DatasheetTemplateRoundTripTests (17) cover the two passes by reading the saved xlsx XML, because what matters is what Kendo reads. One of them is opt-in: given a stored template on disk (ECE_DATASHEET_TEMPLATE_TEST_PATH), it requires the load pass to change nothing GemBox can see. A hand-built workbook did not reproduce the merged-range loss; the real files do, so this test is the guard for it. All nine non-empty templates on PL00026 pass.
Known limits and operating notes
These limits are accepted. Each one is either rare in real templates or harmless to generated datasheets.
- Deliberate hair-to-thin edits are reverted by the save-side rule (see above). Choose medium or thick, or remove the border first.
- A local Import bypasses both server passes. It replaces the workbook in the browser with a file from disk, so that file's column styles and default font are not prepared, and its rotations are dropped. Saving then stores what Kendo read. Importing through the server (Import Datasheet Template on the grid) is not affected.
- Workbooks written with inline strings import empty. Kendo ignores
t="inlineStr"cells. Excel and SOCKETWorx never write them; some tools (openpyxl) do. - Rotation is kept by position, not by content. Cut, paste and drag-fill do not carry it, and undoing a row or column delete restores the row without its rotation.
- Shared-edge conflicts collapse to one line. Where one cell's bottom border and the cell below's top border differ in Excel, Kendo keeps one. Two such edges were seen in 12 templates.
- Small items Kendo drops: the autofilter name
_FilterDatabase, and picture sizes rounded by about 1 px. - Cells beyond Kendo's 200 by 50 sheet and the template's area that a user types into later get Kendo's default font (Arial 9 pt), not the workbook's old default. Kendo never shows or saves those cells, so only later editing in Excel can reach them.
- After a Kendo upgrade, re-run the round-trip check and drive tests K19 and K24 to K28. The rotation display and the edit guard read Kendo internals and switch themselves off rather than misbehave if those move.
