Commit Graph

12 Commits

Author SHA1 Message Date
Atanas Korchev
609622692e Add culture-aware editing, display, and formula entry to RadzenSpreadsheet
The spreadsheet engine parsed typed input with the invariant culture while
displaying values with the current culture, breaking the edit round-trip on
non-en-US hosts and making comma-decimal entry (10,50) impossible.

Workbook gains a Culture property (defaults to CurrentCulture) which the
component stamps from its inherited Culture parameter. It drives:

- Cell input parsing (CellData type inference), including day-month date
  handling for cultures where the group and date separators collide (de-DE)
- Edit text and display rendering (GetValue, GetValueAsString, GetDisplayText)
- Number format rendering - format codes stay canonical invariant tokens while
  separators, month names, and AM/PM designators follow the culture
- Formula entry and display via the new FormulaLocalizer (Excel FormulaLocal
  semantics: ';' argument separators and ',' decimals in comma-decimal
  cultures, lenient comma acceptance where unambiguous, canonical invariant
  storage)
- Dialog input (data validation, conditional format, filter) via shared
  conversion helpers on SpreadsheetDialogBase

XLSX and CSV files read and write canonical invariant values regardless of
the workbook culture, including autofit column widths. Malformed formulas now
surface as error trees instead of an unhandled lexer exception. Number format
parsing is cached (hard-bounded) since CellView reparsed per render.

Includes localization demos for the Spreadsheet and Document Processing
sections and culture test suites.

Note: headless code on non-en-US hosts now parses string values with the
host culture; set Workbook.Culture explicitly (or to InvariantCulture) for
host-independent processing.
2026-07-08 14:54:55 +03:00
Atanas Korchev
ffc0e31299 Preserve cell value type on hyperlink command undo
HyperlinkCommand snapshotted cell.Value via .ToString() and restored it
as a string on Unexecute. For non-string values (double, DateTime, bool,
int) this silently converted the original value to a string. Change
the snapshot field to object? and restore as-is.
2026-06-15 18:45:16 +03:00
Atanas Korchev
ce0eae2037 Add RadzenSpreadsheet feature toggles, async command pipeline and custom ribbon
ReadOnly, ShowToolbar, ShowFormulaBar, ShowSheetTabs, and 15 Allow* parameters
gate workbook mutations and grey out the matching tools. Each ICommand declares
its SpreadsheetFeature so ExecuteAsync routes through one chokepoint.

Execute is now async (Task<bool>) so CommandExecuting handlers can await before
calling PreventDefault to veto a command. Tool bindings move from setter-style
dispatch to Value=/ValueChanged= async methods.

ChildContent replaces the built-in ribbon; the host cascades the active
Worksheet so tools in custom content don't need to track sheet-tab changes.
TableDesignTab is a new public component for the contextual tab.

Tests: 76 new (parameter rendering, ExecuteAsync gating per Allow* flag,
CommandExecuting + PreventDefault, ICommand.Feature mapping, ChildContent).
Also fixes two pre-existing SheetViewTests that hardcoded the old 24px row
default after it changed to 22px in 2e79dd7d.
2026-06-15 18:45:14 +03:00
Atanas Korchev
2e0e4e1d32 Enforce sheet and workbook protection in the spreadsheet UI
Add IProtectedCommand interface to all 20 command classes with appropriate
SheetAction mappings. Guard Execute() to block protected actions, guard
Editor.StartEdit() to prevent editing locked cells, guard clipboard paste
and workbook structure operations (add/remove/rename/move sheets).
2026-06-15 18:45:06 +03:00
Atanas Korchev
3ec40b347b Rename Hyperlink.DisplayText to Text 2026-06-15 18:45:06 +03:00
Atanas Korchev
4a70f957c2 Standardize null checks to is null / is not null
Replaced all == null with is null and != null with is not null
across 109 spreadsheet files. The is null pattern uses a direct
reference check that cannot be overridden by operator overloads.
2026-06-15 18:45:05 +03:00
Atanas Korchev
06de769da4 Separate document and UI layers in spreadsheet architecture
- Move 26 command files from Documents/Spreadsheet to Spreadsheet (UI layer)
- Move GetPixelRange/GetIndexRange from Axis to SheetView
- Move Editor from Worksheet to SheetView
- Remove Commands (UndoRedoStack) from Worksheet
- Widen ISpreadsheet with Execute/Undo/Redo so tools don't couple to UndoRedoStack
- Tools use [CascadingParameter] ISpreadsheet for command execution
- Add Worksheet.ImagesChanged event; ImageOverlay uses it instead of Commands.Changed
- Result: zero using Radzen.Blazor.Spreadsheet in Documents/Spreadsheet
2026-06-15 18:45:03 +03:00
Atanas Korchev
5fc3a52908 Move document-layer files to Radzen.Blazor/Documents/Spreadsheet/
137 files with namespace Radzen.Documents.Spreadsheet now live under
Documents/Spreadsheet/ directory, matching their namespace. 76 function
files in Documents/Spreadsheet/Functions/. 27 UI files remain in
Spreadsheet/.
2026-06-15 18:45:03 +03:00
Atanas Korchev
622b24c4f1 Rename Sheet class to Worksheet
Matches Excel terminology, OpenXML spec, and industry convention
(Aspose, Telerik, Syncfusion all use Worksheet). Property names on
components remain Sheet for now; only the type name changes.
2026-06-15 18:45:03 +03:00
Atanas Korchev
d99fdd3fcc Rename namespace to Radzen.Documents.Spreadsheet for document layer
137 document-layer files now use namespace Radzen.Documents.Spreadsheet.
26 UI-layer files keep Radzen.Blazor.Spreadsheet with using added.
Test files add using Radzen.Documents.Spreadsheet.
Sheet class renamed to Worksheet to match industry conventions.
2026-06-15 18:45:02 +03:00
Atanas Korchev
4a261c4ace Optimize CellStore with sparse shift operations and cell eviction
Replace O(rows × columns) nested loops in Sheet.DeleteRow/DeleteColumn/
InsertRow/InsertColumn with sparse dictionary operations that only touch
populated cells. Unify duplicate InvalidateFormulasReferencingRow/Column
into a single method.

Fix TryGet to not auto-create cells on read access — prevents dictionary
bloat from formula evaluation, export, and clipboard operations. Write-path
callers (FormatCommand, BorderCommand, HyperlinkCommand, MergeCellsCommand)
now use the indexer directly. FormulaEvaluator returns empty CellData for
unpopulated in-bounds cells instead of #REF!.

Add Cell.IsEmpty and CellStore.Compact() for explicit eviction of cells
with no value, formula, format, or hyperlink.
2026-06-15 18:45:02 +03:00
Atanas Korchev
97bc6b7949 Add missing formatting features to RadzenSpreadsheet.
Add strikethrough, font family, font size, text wrap, merge cells UI,
cell borders, hyperlinks, number format colors, and conditional
formatting UI. Includes toolbar tools, undo/redo commands, XLSX
import/export, and 45 new tests.
2026-06-15 18:45:01 +03:00