Remove noise comments and non-public XML docs from spreadsheet code

Two sweeps over Radzen.Blazor/Documents/Spreadsheet and Radzen.Blazor/Spreadsheet:

- Delete inline `//` comments that merely restate the adjacent code
  (e.g. "// Decrease column count" above `ColumnCount--;`, the "// Parse X"
  labels above the matching ParseX(...) calls). Comments explaining *why*,
  Excel/OOXML quirks, ordering requirements and trade-offs are kept.
- Delete XML doc comments (`///`) on non-public declarations — private/internal
  members and the members of internal types (XlsxWriter/Reader, CsvWriter/Reader,
  the formula lexer/parser, the Functions classes, AutofillCommand, etc.). Docs
  on the public API surface are untouched (the build enforces this via CS1591).

Comment-only changes; no behavior change. Build clean, 1477 spreadsheet tests pass.
This commit is contained in:
Atanas Korchev
2026-05-20 12:05:35 +03:00
committed by Vladimir Enchev
parent c03142df75
commit dc699e9518
36 changed files with 6 additions and 412 deletions

View File

@@ -16,9 +16,6 @@ public class Axis(double size, int count)
/// </summary>
public double Size => size;
/// <summary>
/// The total number of items along this axis.
/// </summary>
private int count = count;
/// <summary>
@@ -164,11 +161,6 @@ public class Axis(double size, int count)
}
}
/// <summary>
/// Shifts custom sizes and hidden state up after a row/column is deleted.
/// Entries at the deleted index are removed; entries above are unchanged;
/// entries below are decremented by one.
/// </summary>
internal void ShiftUp(int deletedIndex)
{
var newData = new Dictionary<int, double>();
@@ -207,10 +199,6 @@ public class Axis(double size, int count)
hidden.UnionWith(newHidden);
}
/// <summary>
/// Shifts custom sizes and hidden state down after rows/columns are inserted.
/// Entries at or after the insert point are incremented by count.
/// </summary>
internal void ShiftDown(int fromIndex, int count)
{
var newData = new Dictionary<int, double>();
@@ -247,14 +235,8 @@ public class Axis(double size, int count)
hidden.UnionWith(newHidden);
}
/// <summary>
/// Returns the indices of all items with a custom (non-default) size.
/// </summary>
internal IEnumerable<int> GetCustomSizedIndices() => data.Keys;
/// <summary>
/// Returns the indices of all hidden items.
/// </summary>
internal IEnumerable<int> GetHiddenIndices() => hidden;
/// <summary>

View File

@@ -266,9 +266,6 @@ public class Cell
/// </summary>
public IReadOnlyList<string> ValidationErrors { get; private set; } = [];
/// <summary>
/// Clears the validation errors for the cell.
/// </summary>
internal void ClearValidationErrors()
{
ValidationErrors = [];

View File

@@ -402,9 +402,6 @@ public class CellData : IComparable, IComparable<CellData>
/// </summary>
public bool IsError => Type == CellDataType.Error;
/// <summary>
/// Checks if this cell data is equal to another cell data.
/// </summary>
internal bool IsEqualTo(CellData other)
{
ArgumentNullException.ThrowIfNull(other);
@@ -427,10 +424,6 @@ public class CellData : IComparable, IComparable<CellData>
return ((IComparable)Value!).CompareTo(other.Value) == 0;
}
/// <summary>
/// Checks if this cell data is less than another cell data.
/// </summary>
/// <param name="other"></param>
internal bool IsLessThan(CellData other)
{
ArgumentNullException.ThrowIfNull(other);
@@ -443,10 +436,6 @@ public class CellData : IComparable, IComparable<CellData>
return compareResult < 0;
}
/// <summary>
/// Checks if this cell data is greater than another cell data.
/// </summary>
/// <param name="other"></param>
internal bool IsGreaterThan(CellData other)
{
ArgumentNullException.ThrowIfNull(other);
@@ -459,10 +448,6 @@ public class CellData : IComparable, IComparable<CellData>
return compareResult > 0;
}
/// <summary>
/// Checks if this cell data is less than or equal to another cell data.
/// </summary>
/// <param name="other"></param>
internal bool IsLessThanOrEqualTo(CellData other)
{
ArgumentNullException.ThrowIfNull(other);
@@ -475,10 +460,6 @@ public class CellData : IComparable, IComparable<CellData>
return compareResult <= 0;
}
/// <summary>
/// Checks if this cell data is greater than or equal to another cell data.
/// </summary>
/// <param name="other"></param>
internal bool IsGreaterThanOrEqualTo(CellData other)
{
ArgumentNullException.ThrowIfNull(other);
@@ -528,11 +509,6 @@ public class CellData : IComparable, IComparable<CellData>
/// </summary>
public static CellData FromError(CellError error) => new(error, CellDataType.Error);
/// <summary>
/// Checks if this cell data matches the specified criteria.
/// </summary>
/// <param name="criteria">The criteria to match against</param>
/// <returns>True if this cell matches the criteria, false otherwise</returns>
internal bool MatchesCriteria(CellData criteria)
{
ArgumentNullException.ThrowIfNull(criteria);
@@ -568,7 +544,6 @@ public class CellData : IComparable, IComparable<CellData>
}
}
// Default comparison
return IsEqualTo(criteria);
}
@@ -623,7 +598,6 @@ public class CellData : IComparable, IComparable<CellData>
return false;
}
// Parse the value
if (!double.TryParse(valueStr, out var numericValue))
{
return false;
@@ -644,7 +618,6 @@ public class CellData : IComparable, IComparable<CellData>
return false;
}
// Perform the comparison
return operatorStr switch
{
">" => cellValue > numericValue,

View File

@@ -113,16 +113,8 @@ public class CellStore(Worksheet sheet)
return false;
}
/// <summary>
/// Returns all populated cells in the store without creating new cells.
/// </summary>
internal IEnumerable<Cell> GetPopulatedCells() => data.Values;
/// <summary>
/// Removes all empty cells from the store, freeing memory.
/// A cell is empty when it has no value, formula, format, or hyperlink.
/// </summary>
/// <returns>The number of cells removed.</returns>
internal int Compact()
{
var keysToRemove = new List<(int row, int column)>();
@@ -143,20 +135,10 @@ public class CellStore(Worksheet sheet)
return keysToRemove.Count;
}
/// <summary>
/// Returns the number of populated cells in the store.
/// </summary>
internal int PopulatedCount => data.Count;
/// <summary>
/// Checks if a cell exists at the specified position without creating it.
/// </summary>
internal bool HasCell(int row, int column) => data.ContainsKey((row, column));
/// <summary>
/// Removes all cells at the specified row and shifts cells from higher rows up by one.
/// Only touches populated cells, making this O(populated) instead of O(rows × columns).
/// </summary>
internal void ShiftRowsUp(int deletedRow)
{
var toRemove = new List<(int row, int column)>();
@@ -188,10 +170,6 @@ public class CellStore(Worksheet sheet)
}
}
/// <summary>
/// Shifts all cells at or after the specified row down by the given count.
/// Only touches populated cells, making this O(populated) instead of O(rows × columns).
/// </summary>
internal void ShiftRowsDown(int fromRow, int count)
{
var toRekey = new List<((int row, int column) key, Cell cell)>();
@@ -219,10 +197,6 @@ public class CellStore(Worksheet sheet)
}
}
/// <summary>
/// Removes all cells at the specified column and shifts cells from higher columns left by one.
/// Only touches populated cells, making this O(populated) instead of O(rows × columns).
/// </summary>
internal void ShiftColumnsLeft(int deletedColumn)
{
var toRemove = new List<(int row, int column)>();
@@ -254,10 +228,6 @@ public class CellStore(Worksheet sheet)
}
}
/// <summary>
/// Shifts all cells at or after the specified column right by the given count.
/// Only touches populated cells, making this O(populated) instead of O(rows × columns).
/// </summary>
internal void ShiftColumnsRight(int fromColumn, int count)
{
var toRekey = new List<((int row, int column) key, Cell cell)>();

View File

@@ -6,7 +6,6 @@ namespace Radzen.Documents.Spreadsheet;
#nullable enable
/// <summary>Reads a CSV stream into a <see cref="Workbook"/> with a single sheet.</summary>
static class CsvReader
{
public static Workbook Read(Stream stream, CsvImportOptions options)

View File

@@ -8,7 +8,6 @@ namespace Radzen.Documents.Spreadsheet;
#nullable enable
/// <summary>Writes a single <see cref="Worksheet"/> to a stream in CSV format.</summary>
class CsvWriter(Worksheet sheet, CsvExportOptions options)
{
public void Write(Stream stream)

View File

@@ -29,7 +29,6 @@ public class DataCellStore<T>(DataSheet<T> sheet, int pageSize = 20) : CellStore
Skip = pageNumber * pageSize
});
// Populate cells for the loaded page
for (var i = 0; i < data.Count; i++)
{
var dataItem = data[i];

View File

@@ -272,9 +272,6 @@ public class Format
Locked is null &&
FormulaHidden is null;
/// <summary>
/// Occurs when the format is changed, allowing for updates to be made to the UI or other components that depend on this format.
/// </summary>
internal event Action? Changed;
internal Format Merge(Format format)

View File

@@ -5,14 +5,8 @@ namespace Radzen.Documents.Spreadsheet;
#nullable enable
/// <summary>
/// Builds format codes from UI state for the Format Cells dialog.
/// </summary>
internal static class FormatCodeBuilder
{
/// <summary>
/// Builds a format code string from the given parameters.
/// </summary>
public static string Build(NumberFormatCategory category, int decimalPlaces = 2,
bool useThousandsSeparator = true, string currencySymbol = "$",
string? selectedPreset = null)
@@ -46,8 +40,5 @@ internal static class FormatCodeBuilder
return $"{pos};{neg};{zero};{text}";
}
/// <summary>
/// Gets the available currency symbols.
/// </summary>
public static IReadOnlyList<string> CurrencySymbols { get; } = ["$", "\u20AC", "\u00A3", "\u00A5"];
}

View File

@@ -408,7 +408,6 @@ class FormulaEvaluator(Worksheet sheet, Cell currentCell) : IFormulaSyntaxNodeVi
return null; // Error already set
}
// Set the argument based on parameter type
if (paramDef.Type == ParameterType.Collection)
{
if (argumentNodes[argumentIndex] is CellSyntaxNode cellNode)
@@ -427,7 +426,6 @@ class FormulaEvaluator(Worksheet sheet, Cell currentCell) : IFormulaSyntaxNodeVi
}
else if (!paramDef.IsRequired)
{
// Optional parameter not provided - skip it
continue;
}
}

View File

@@ -4,10 +4,6 @@ using System.Collections.Generic;
namespace Radzen.Documents.Spreadsheet;
/// <summary>
/// Shared implementation for VLOOKUP and HLOOKUP.
/// Subclasses provide the axis-specific details via a few one-liner overrides.
/// </summary>
abstract class LookupFunctionBase : FormulaFunction
{
public override FunctionParameter[] Parameters =>
@@ -18,28 +14,12 @@ abstract class LookupFunctionBase : FormulaFunction
new("is_sorted", ParameterType.Single, isRequired: false)
];
/// <summary>
/// Returns (searchCount, resultCount) from the range dimensions.
/// VLOOKUP searches rows and indexes columns; HLOOKUP is the opposite.
/// </summary>
protected abstract (int searchCount, int resultCount) GetSearchAndResultCounts(int rows, int columns);
/// <summary>
/// Returns fallback (rows, columns) when the range is not a RangeList.
/// VLOOKUP assumes a single-column vector; HLOOKUP assumes a single-row vector.
/// </summary>
protected abstract (int rows, int columns) GetFallbackDimensions(int count);
/// <summary>
/// Returns the flat index into the range for the search cell at position <paramref name="i"/>
/// along the search axis (row 0 for HLOOKUP, column 0 for VLOOKUP).
/// </summary>
protected abstract int GetSearchCellIndex(int i, int columns);
/// <summary>
/// Returns the flat index into the range for the result cell given the matched search
/// position and the 1-based requested index.
/// </summary>
protected abstract int GetResultCellIndex(int matchPosition, int requestedIndex, int columns);
public override CellData Evaluate(FunctionArguments arguments)

View File

@@ -70,7 +70,6 @@ class SubstituteFunction : FormulaFunction
count++;
if (count == instanceNum)
{
// Build result: prefix + newText + suffix after oldText
var prefix = text.Substring(0, index);
var suffix = text.Substring(index + oldText.Length);
return CellData.FromString(prefix + newText + suffix);

View File

@@ -45,22 +45,18 @@ class SumIfFunction : FormulaFunction
var rangeCell = range[i];
var sumCell = actualSumRange[i];
// Skip if range cell has an error
if (rangeCell.IsError)
{
return rangeCell;
}
// Skip if sum cell has an error
if (sumCell.IsError)
{
return sumCell;
}
// Check if the range cell matches the criteria
if (rangeCell.MatchesCriteria(criteria))
{
// Add the corresponding sum cell value if it's a number
if (sumCell.Type == CellDataType.Number)
{
sum += sumCell.GetValueOrDefault<double>();
@@ -68,7 +64,6 @@ class SumIfFunction : FormulaFunction
// If sum cell is empty, treat as 0
else if (sumCell.IsEmpty)
{
// Do nothing, effectively adding 0
}
// If sum cell is not a number and not empty, skip it
}

View File

@@ -106,11 +106,6 @@ public class MergedCellStore
/// </summary>
public List<RangeRef> GetOverlappingRanges(RangeRef range) => [.. data.Where(range.Overlaps)];
/// <summary>
/// Adjusts all merged ranges after a row is deleted.
/// Ranges fully on the deleted row are removed. Ranges spanning the deleted row shrink.
/// Ranges below the deleted row shift up by one.
/// </summary>
internal void ShiftRowsUp(int deletedRow)
{
for (int i = data.Count - 1; i >= 0; i--)
@@ -147,10 +142,6 @@ public class MergedCellStore
}
}
/// <summary>
/// Adjusts all merged ranges after rows are inserted.
/// Ranges at or below the insert point shift down by count.
/// </summary>
internal void ShiftRowsDown(int fromRow, int count)
{
for (int i = 0; i < data.Count; i++)
@@ -177,9 +168,6 @@ public class MergedCellStore
}
}
/// <summary>
/// Adjusts all merged ranges after a column is deleted.
/// </summary>
internal void ShiftColumnsLeft(int deletedColumn)
{
for (int i = data.Count - 1; i >= 0; i--)
@@ -211,9 +199,6 @@ public class MergedCellStore
}
}
/// <summary>
/// Adjusts all merged ranges after columns are inserted.
/// </summary>
internal void ShiftColumnsRight(int fromColumn, int count)
{
for (int i = 0; i < data.Count; i++)

View File

@@ -129,9 +129,6 @@ public static class NumberFormat
return result;
}
/// <summary>
/// Determines whether a format code represents a date/time format.
/// </summary>
internal static bool IsDateFormat(string formatCode)
{
if (string.IsNullOrEmpty(formatCode))
@@ -375,30 +372,25 @@ public static class NumberFormat
var absValue = Math.Abs(value);
var isNegative = value < 0;
// Percentage: multiply by 100
if (section.IsPercentage)
{
absValue *= 100;
}
// Thousands scaling
for (var i = 0; i < section.ThousandsScale; i++)
{
absValue /= 1000;
}
// Count integer and decimal placeholders
var intZeros = section.IntegerZeros;
var intHashes = section.IntegerHashes;
var decimalPlaces = section.DecimalPlaces;
var hasThousands = section.HasThousandsSeparator;
// Round to decimal places
absValue = Math.Round(absValue, decimalPlaces, MidpointRounding.AwayFromZero);
var sb = new StringBuilder();
// Prefix literals
sb.Append(section.Prefix);
// Add negative sign if this is a single-section format and value is negative
@@ -413,14 +405,11 @@ public static class NumberFormat
// parens are part of the format literals
}
// Split into integer and decimal parts
var intPart = (long)Math.Truncate(absValue);
var fracPart = absValue - Math.Truncate(absValue);
// Format integer part
var intStr = intPart.ToString(CultureInfo.InvariantCulture);
// Pad with zeros
var minIntDigits = Math.Max(intZeros, 1);
if (intZeros == 0 && intHashes > 0 && intPart == 0)
{
@@ -433,7 +422,6 @@ public static class NumberFormat
intStr = intStr.PadLeft(intZeros, '0');
}
// Add thousands separators
if (hasThousands && intStr.Length > 0)
{
var formatted = new StringBuilder(intStr.Length + (intStr.Length - 1) / 3);
@@ -451,7 +439,6 @@ public static class NumberFormat
sb.Append(intStr);
// Format decimal part
if (decimalPlaces > 0)
{
sb.Append('.');
@@ -511,7 +498,6 @@ public static class NumberFormat
}
}
// Suffix (%, etc.)
sb.Append(section.Suffix);
return sb.ToString();
@@ -546,7 +532,6 @@ public static class NumberFormat
mantissa = absValue / Math.Pow(10, exponent);
}
// Round mantissa to DecimalPlaces
mantissa = Math.Round(mantissa, section.DecimalPlaces, MidpointRounding.AwayFromZero);
// Check if rounding carried over (e.g., 9.995 → 10.00)
@@ -563,7 +548,6 @@ public static class NumberFormat
}
}
// Format mantissa
if (section.DecimalPlaces > 0)
{
sb.Append(mantissa.ToString("F" + section.DecimalPlaces, CultureInfo.InvariantCulture));
@@ -573,11 +557,10 @@ public static class NumberFormat
sb.Append(((long)Math.Round(mantissa)).ToString(CultureInfo.InvariantCulture));
}
// Format exponent part (e.g. "E+00")
var expFormat = section.ExponentFormat;
var expChar = expFormat[0]; // E or e
var expSign = expFormat[1]; // + or -
var expDigits = expFormat.Length - 2; // number of 0/# after sign
var expChar = expFormat[0];
var expSign = expFormat[1];
var expDigits = expFormat.Length - 2;
sb.Append(expChar);

View File

@@ -6,9 +6,6 @@ namespace Radzen.Documents.Spreadsheet;
#nullable enable
/// <summary>
/// Parses Excel-compatible number format codes into structured <see cref="FormatSection"/> objects.
/// </summary>
static class NumberFormatParser
{
public static ParsedFormat Parse(string formatCode)
@@ -250,7 +247,6 @@ static class NumberFormatParser
{
var c = section[i];
// Escaped character
if (c == '\\' && i + 1 < section.Length)
{
tokens.Add(new FormatToken(TokenType.Literal, section[i + 1].ToString()));
@@ -258,7 +254,6 @@ static class NumberFormatParser
continue;
}
// Quoted literal
if (c == '"')
{
var end = section.IndexOf('"', i + 1);
@@ -295,7 +290,6 @@ static class NumberFormatParser
continue;
}
// AM/PM
if (i + 4 < section.Length &&
section.Substring(i, 5).Equals("AM/PM", StringComparison.OrdinalIgnoreCase))
{
@@ -352,7 +346,6 @@ static class NumberFormatParser
}
else
{
// Look ahead for s
for (var j = i + len; j < section.Length; j++)
{
var nc = section[j];
@@ -447,7 +440,7 @@ static class NumberFormatParser
if (c is 'E' or 'e' && i + 1 < section.Length && section[i + 1] is '+' or '-')
{
var start = i;
i += 2; // skip E and sign
i += 2;
while (i < section.Length && section[i] is '0' or '#')
{
i++;

View File

@@ -5,34 +5,19 @@ namespace Radzen.Documents.Spreadsheet;
#nullable enable
/// <summary>
/// Categories of number format codes.
/// </summary>
internal enum NumberFormatCategory
{
/// <summary>General format (no specific formatting).</summary>
General,
/// <summary>Number formats (e.g. 0, 0.00, #,##0).</summary>
Number,
/// <summary>Currency formats (e.g. $#,##0.00).</summary>
Currency,
/// <summary>Accounting formats (e.g. _($* #,##0.00_)).</summary>
Accounting,
/// <summary>Percentage formats (e.g. 0%, 0.00%).</summary>
Percentage,
/// <summary>Scientific formats (e.g. 0.00E+00).</summary>
Scientific,
/// <summary>Date formats (e.g. mm/dd/yyyy).</summary>
Date,
/// <summary>Time formats (e.g. h:mm AM/PM).</summary>
Time,
/// <summary>Text format.</summary>
Text
}
/// <summary>
/// Provides mappings between Excel built-in numFmtId values and format codes.
/// </summary>
internal static class NumberFormatPresets
{
private static readonly Dictionary<int, string> IdToCode = new()
@@ -74,28 +59,17 @@ internal static class NumberFormatPresets
return map;
}
/// <summary>
/// Gets the format code for a built-in numFmtId.
/// Returns null for unknown IDs.
/// </summary>
public static string? GetFormatCode(int numFmtId)
{
return IdToCode.TryGetValue(numFmtId, out var code) ? code : null;
}
/// <summary>
/// Gets the numFmtId for a known format code.
/// Returns -1 for unknown format codes.
/// </summary>
public static int GetNumFmtId(string formatCode)
{
ArgumentNullException.ThrowIfNull(formatCode);
return CodeToId.TryGetValue(formatCode, out var id) ? id : -1;
}
/// <summary>
/// Determines the category of a format code.
/// </summary>
public static NumberFormatCategory GetCategory(string? formatCode)
{
if (string.IsNullOrEmpty(formatCode) ||
@@ -146,9 +120,6 @@ internal static class NumberFormatPresets
return NumberFormatCategory.Number;
}
/// <summary>
/// Gets the preset format codes for a given category.
/// </summary>
public static IReadOnlyList<(string Name, string FormatCode)> GetPresets(NumberFormatCategory category)
{
return category switch

View File

@@ -5,41 +5,18 @@ using System.Collections.Generic;
namespace Radzen.Documents.Spreadsheet;
/// <summary>
/// Represents a list of cell data originating from a rectangular range, carrying its row/column dimensions.
/// </summary>
internal class RangeList : List<CellData>
{
private readonly Worksheet sheet;
internal Worksheet Worksheet => sheet;
/// <summary>
/// Number of rows in the range.
/// </summary>
public int Rows { get; }
/// <summary>
/// Number of columns in the range.
/// </summary>
public int Columns { get; }
/// <summary>
/// Starting row (absolute) of the range in the sheet.
/// </summary>
public int StartRow { get; }
/// <summary>
/// Starting column (absolute) of the range in the sheet.
/// </summary>
public int StartColumn { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RangeList"/> class with specified dimensions.
/// </summary>
/// <param name="rows">Number of rows in the range.</param>
/// <param name="columns">Number of columns in the range.</param>
/// <param name="startRow">Starting row index.</param>
/// <param name="startColumn">Starting column index.</param>
/// <param name="sheet">The sheet instance providing row visibility information.</param>
public RangeList(int rows, int columns, int startRow, int startColumn, Worksheet sheet)
{
Rows = rows;
@@ -49,9 +26,6 @@ internal class RangeList : List<CellData>
this.sheet = sheet;
}
/// <summary>
/// Returns true if the row corresponding to the specified item index is hidden.
/// </summary>
public bool IsRowHiddenAt(int itemIndex)
{
var rowOffset = itemIndex / Math.Max(1, Columns);

View File

@@ -30,18 +30,10 @@ public class Selection(Worksheet sheet)
/// </summary>
public event Action? RangeFinalized;
/// <summary>
/// Notifies subscribers that the user has finished a selection gesture
/// (pointer-up after a click or drag).
/// </summary>
internal void FinalizeRange() => RangeFinalized?.Invoke();
private bool pendingChange;
/// <summary>
/// Updates the selection to a new cell address and triggers a change event.
/// </summary>
/// <param name="address"></param>
internal void Update(CellRef address)
{
Cell = address;
@@ -49,12 +41,6 @@ public class Selection(Worksheet sheet)
TriggerChange();
}
/// <summary>
/// Re-raises the change event after a row/column insert or delete has swapped the cell
/// occupying the current selection. The selection coordinates stay the same, but the cell
/// beneath them is now a different one, so selection-dependent UI (the formula bar, toolbar
/// state) must re-read the active cell. Honours the sheet's batch update like other changes.
/// </summary>
internal void NotifyContentChanged() => TriggerChange();
internal void TriggerPendingChange()
@@ -79,9 +65,6 @@ public class Selection(Worksheet sheet)
}
}
/// <summary>
/// Moves the selection by a specified number of rows and columns.
/// </summary>
internal CellRef Move(int rowOffset, int columnOffset)
{
var column = OffsetColumn(columnOffset);
@@ -112,9 +95,6 @@ public class Selection(Worksheet sheet)
};
}
/// <summary>
/// Cycles through the selection within the current range, moving by the specified row and column offsets.
/// </summary>
internal CellRef Cycle(int rowOffset, int columnOffset)
{
if (Cell == CellRef.Invalid)
@@ -197,9 +177,6 @@ public class Selection(Worksheet sheet)
TriggerChange();
}
/// <summary>
/// Checks if the specified address is within the active selection range.
/// </summary>
internal bool IsActive(ColumnRef address) => Range.Contains(address);
internal bool IsActive(RowRef address) => Range.Contains(address);
@@ -298,9 +275,6 @@ public class Selection(Worksheet sheet)
TriggerChange();
}
/// <summary>
/// Extends the current selection by a specified number of rows and columns, adjusting the active cell and range accordingly.
/// </summary>
internal CellRef Extend(int rowOffset, int columnOffset)
{
if (Cell == CellRef.Invalid || Range == RangeRef.Invalid)

View File

@@ -601,17 +601,11 @@ public class TableColumn
/// </summary>
public class AutoFilter
{
/// <summary>
/// Initializes a new instance of the <see cref="AutoFilter"/> class.
/// </summary>
internal AutoFilter(Worksheet sheet)
{
Worksheet = sheet;
}
/// <summary>
/// Initializes a new instance of the <see cref="AutoFilter"/> class with a range.
/// </summary>
internal AutoFilter(Worksheet sheet, RangeRef range)
{
Worksheet = sheet;

View File

@@ -22,9 +22,6 @@ public partial class Worksheet
private readonly HashSet<int> invalidReferenceRows = [];
private readonly HashSet<int> invalidReferenceColumns = [];
/// <summary>
/// Gets a value indicating whether the sheet is currently being updated.
/// </summary>
internal bool IsUpdating { get; private set; }
private bool isEvaluating;
@@ -117,9 +114,6 @@ public partial class Worksheet
}
}
/// <summary>
/// Occurs when the selected image changes.
/// </summary>
internal event Action? SelectedImageChanged;
internal event Action? ImagesChanged;
@@ -161,9 +155,6 @@ public partial class Worksheet
}
}
/// <summary>
/// Occurs when the selected chart changes.
/// </summary>
internal event Action? SelectedChartChanged;
internal event Action? ChartsChanged;
@@ -194,9 +185,6 @@ public partial class Worksheet
private readonly HashSet<int> filteredColumns = [];
/// <summary>
/// Gets the set of columns that have filters applied.
/// </summary>
internal IReadOnlySet<int> FilteredColumns => filteredColumns;
/// <summary>
@@ -281,11 +269,6 @@ public partial class Worksheet
AutoFilter = new(this);
}
/// <summary>
/// Clamps the specified cell address to ensure it is within the bounds of the sheet.
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
internal CellRef Clamp(CellRef address)
{
var row = Math.Max(0, Math.Min(RowCount - 1, address.Row));
@@ -346,9 +329,6 @@ public partial class Worksheet
}
}
/// <summary>
/// Notifies populated cells in the given range that they should re-validate and/or refresh.
/// </summary>
internal void RefreshCells(RangeRef range, bool validate = false)
{
foreach (var cellRef in range.GetCells())
@@ -388,13 +368,6 @@ public partial class Worksheet
Selection.TriggerPendingChange();
}
/// <summary>
/// Gets a delimited string representation of the specified range in the sheet.
/// </summary>
/// <param name="range"></param>
/// <param name="rowDelimiter"></param>
/// <param name="cellDelimiter"></param>
/// <returns></returns>
internal string GetDelimitedString(RangeRef range, string rowDelimiter = "\n", string cellDelimiter = "\t")
{
ArgumentNullException.ThrowIfNull(rowDelimiter);
@@ -430,13 +403,6 @@ public partial class Worksheet
return result.ToString().TrimEnd(rowDelimiter.ToCharArray());
}
/// <summary>
/// Inserts a delimited string into the specified cell address in the sheet, splitting the string into rows and cells based on the specified delimiters.
/// </summary>
/// <param name="address"></param>
/// <param name="value"></param>
/// <param name="cellDelimiter"></param>
internal void InsertDelimitedString(CellRef address, string value, string cellDelimiter = "\t")
{
ArgumentNullException.ThrowIfNull(value);
@@ -477,16 +443,13 @@ public partial class Worksheet
// Shift column metadata (custom widths, hidden state)
Columns.ShiftUp(columnIndex);
// Shift merged cell ranges
MergedCells.ShiftColumnsLeft(columnIndex);
// Mark deleted column index as invalid for references
invalidReferenceColumns.Add(columnIndex);
// Any formulas that reference this column should be turned into =#REF!
InvalidateFormulasReferencing(column: columnIndex);
// Decrease column count
ColumnCount--;
// A different cell now occupies the selection if it sat at or after the deleted
@@ -519,16 +482,13 @@ public partial class Worksheet
// Shift row metadata (custom heights, hidden state)
Rows.ShiftUp(rowIndex);
// Shift merged cell ranges
MergedCells.ShiftRowsUp(rowIndex);
// Mark deleted row index as invalid for references
invalidReferenceRows.Add(rowIndex);
// Any formulas that reference this row should be turned into =#REF!
InvalidateFormulasReferencing(row: rowIndex);
// Decrease row count
RowCount--;
// A different cell now occupies the selection if it sat at or after the deleted
@@ -753,7 +713,6 @@ public partial class Worksheet
// Shift row metadata (custom heights, hidden state)
Rows.ShiftDown(rowIndex, count);
// Shift merged cell ranges
MergedCells.ShiftRowsDown(rowIndex, count);
// Adjust formulas: shift row indices at or after the insert point
@@ -807,7 +766,6 @@ public partial class Worksheet
// Shift column metadata (custom widths, hidden state)
Columns.ShiftDown(columnIndex, count);
// Shift merged cell ranges
MergedCells.ShiftColumnsRight(columnIndex, count);
// Adjust formulas: shift column indices at or after the insert point
@@ -845,7 +803,6 @@ public partial class Worksheet
public static string Rewrite(string original, FormulaSyntaxTree tree, Func<FormulaToken, CellRef> adjust)
{
var rewriter = new FormulaRewriter(adjust);
// Always start with '=' for formulas
rewriter.builder.Append('=');
tree.Root.Accept(rewriter);
return rewriter.builder.ToString();
@@ -904,7 +861,6 @@ public partial class Worksheet
public override void VisitRange(RangeSyntaxNode rangeSyntaxNode)
{
// Adjust both sides using the provided delegate
var startToken = rangeSyntaxNode.Start.Token;
var endToken = rangeSyntaxNode.End.Token;

View File

@@ -9,9 +9,6 @@ namespace Radzen.Documents.Spreadsheet;
#nullable enable
/// <summary>
/// Reads a <see cref="Workbook"/> from a stream in the Open XML Spreadsheet format (XLSX).
/// </summary>
static class XlsxReader
{
private const double EmuPerPixel = 9525.0;
@@ -334,37 +331,27 @@ static class XlsxReader
var sheetDoc = XDocument.Load(sheetStream);
var sNs = sheetDoc.Root!.Name.Namespace;
// Parse default row height
var defaultRowHeight = ParseDefaultRowHeight(sheetDoc, sNs);
// Parse frozen panes
ParseFrozenPanes(sheetDoc, sNs, sheet);
// Parse column widths
ParseColumnWidths(sheetDoc, sNs, sheet);
// Parse rows and cells
ParseRowsAndCells(sheetDoc, sNs, sheet, styleInfo, sharedStrings, defaultRowHeight);
// Parse merged cells
ParseMergedCells(sheetDoc, sNs, sheet);
// Parse auto filter
ParseAutoFilter(sheetDoc, sNs, sheet);
// Parse data validations
ParseDataValidations(sheetDoc, sNs, sheet);
// Parse hyperlinks
ParseHyperlinks(archive, sheetInfo, sheetDoc, sNs, sheet);
// Parse drawings (images)
ParseDrawings(archive, sheetInfo, sheetDoc, sNs, sheet);
// Parse tables (must run after rows/cells so column-name fallback can read header values)
ParseTables(archive, sheetInfo, sheetDoc, sNs, sheet);
// Parse sheet protection
ParseSheetProtection(sheetDoc, sNs, sheet);
sheet.Name = sheetInfo.Name;
@@ -373,7 +360,6 @@ static class XlsxReader
private static double ParseDefaultRowHeight(XDocument sheetDoc, XNamespace sNs)
{
// Parse default row height from sheet format properties
var defaultRowHeight = 20.0; // Default fallback
var sheetFormatPr = sheetDoc.Descendants(sNs + "sheetFormatPr").FirstOrDefault();
if (sheetFormatPr is not null)
@@ -622,7 +608,6 @@ static class XlsxReader
var range = RangeRef.Parse(refAttribute);
sheet.AutoFilter.Range = range;
// Load filter columns
var filterColumns = autoFilterElement.Elements(sNs + "filterColumn").ToList();
foreach (var filterColumn in filterColumns)
{
@@ -730,7 +715,6 @@ static class XlsxReader
return;
}
// Load sheet relationships
var relMap = new Dictionary<string, string>();
var sheetFileName = sheetInfo.FullPath.Split('/').Last();
var relsPath = $"xl/worksheets/_rels/{sheetFileName}.rels";
@@ -850,7 +834,6 @@ static class XlsxReader
}
}
// Parse drawing XML
XNamespace xdr = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
XNamespace a = "http://schemas.openxmlformats.org/drawingml/2006/main";
@@ -873,7 +856,6 @@ static class XlsxReader
continue;
}
// Parse anchor positions
var from = ParseCellAnchor(anchor.Element(xdr + "from"), xdr);
if (from is null)
{
@@ -947,7 +929,6 @@ static class XlsxReader
continue;
}
// Resolve image path
var imagePath = ResolvePath(drawingDir + "/", imageTarget);
var imageEntry = archive.GetEntry(imagePath);
if (imageEntry is null)
@@ -955,13 +936,11 @@ static class XlsxReader
continue;
}
// Read image data
using var imageStream = imageEntry.Open();
using var ms = new System.IO.MemoryStream();
imageStream.CopyTo(ms);
image.Data = ms.ToArray();
// Determine content type from extension
var ext2 = imagePath.Split('.').Last().ToLowerInvariant();
image.ContentType = ext2 switch
{
@@ -975,7 +954,6 @@ static class XlsxReader
_ => "image/png"
};
// Parse name/description
var nvPicPr = pic.Element(xdr + "nvPicPr");
var cNvPr = nvPicPr?.Element(xdr + "cNvPr");
image.Name = cNvPr?.Attribute("name")?.Value;
@@ -1060,14 +1038,12 @@ static class XlsxReader
return chart;
}
// Parse title
var titleElement = chartElement.Element(c + "title");
if (titleElement is not null)
{
chart.Title = ParseChartTitle(titleElement, c, a);
}
// Parse legend
var legendElement = chartElement.Element(c + "legend");
if (legendElement is not null)
{
@@ -1083,7 +1059,6 @@ static class XlsxReader
};
}
// Parse plot area
var plotArea = chartElement.Element(c + "plotArea");
if (plotArea is null)
{
@@ -1113,7 +1088,6 @@ static class XlsxReader
chart.ChartType = chartType.Value;
// Parse series
foreach (var ser in groupElement.Elements(c + "ser"))
{
var series = ParseChartSeries(ser, c, a);
@@ -1195,14 +1169,12 @@ static class XlsxReader
{
var series = new ChartSeries();
// Parse index
var idx = ser.Element(c + "idx")?.Attribute("val")?.Value;
if (idx is not null && int.TryParse(idx, out var index))
{
series.Index = index;
}
// Parse title
var tx = ser.Element(c + "tx");
if (tx is not null)
{
@@ -1217,7 +1189,6 @@ static class XlsxReader
}
}
// Parse categories
var cat = ser.Element(c + "cat");
if (cat is not null)
{
@@ -1240,7 +1211,6 @@ static class XlsxReader
}
}
// Parse values
var val = ser.Element(c + "val");
if (val is not null)
{

View File

@@ -9,9 +9,6 @@ namespace Radzen.Documents.Spreadsheet;
#nullable enable
/// <summary>
/// Writes a <see cref="Workbook"/> to a stream in the Open XML Spreadsheet format (XLSX).
/// </summary>
class XlsxWriter(Workbook sourceWorkbook)
{
private const double EmuPerPixel = 9525.0;
@@ -258,7 +255,6 @@ class XlsxWriter(Workbook sourceWorkbook)
mediaPath = $"xl/media/image{globalMediaIndex++}.{ext}";
mediaMap[hash] = mediaPath;
// Write image bytes to archive
using (var mediaEntry = archive.CreateEntry(mediaPath).Open())
{
mediaEntry.Write(image.Data, 0, image.Data.Length);
@@ -269,7 +265,6 @@ class XlsxWriter(Workbook sourceWorkbook)
var relTarget = "../media/" + mediaPath.Split('/').Last();
drawingRels.Add((imageRelId, relTarget, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"));
// Build anchor element
XElement anchorElement;
var fromElement = new XElement(xdr + "from",
new XElement(xdr + "col", image.From.Column.ToString(CultureInfo.InvariantCulture)),
@@ -328,7 +323,6 @@ class XlsxWriter(Workbook sourceWorkbook)
drawingDoc.Root!.Add(anchorElement);
}
// Write chart anchors
var chartIndex = 1;
foreach (var chart in sheet.Charts)
{
@@ -338,7 +332,6 @@ class XlsxWriter(Workbook sourceWorkbook)
drawingRels.Add((chartRelId, $"../charts/{chartFileName}", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"));
// Build anchor element
var fromElement = new XElement(xdr + "from",
new XElement(xdr + "col", chart.From.Column.ToString(CultureInfo.InvariantCulture)),
new XElement(xdr + "colOff", PixelsToEmu(chart.From.ColumnOffset)),
@@ -389,19 +382,16 @@ class XlsxWriter(Workbook sourceWorkbook)
drawingDoc.Root!.Add(chartAnchor);
// Save chart XML
SaveChartXml(archive, chart, chartPath);
chartIndex++;
}
// Save drawing XML
using (var entry = archive.CreateEntry($"xl/drawings/drawing{drawingIndex}.xml").Open())
{
drawingDoc.Save(entry);
}
// Save drawing relationships
if (drawingRels.Count > 0)
{
var pkgNs = "http://schemas.openxmlformats.org/package/2006/relationships";
@@ -450,7 +440,6 @@ class XlsxWriter(Workbook sourceWorkbook)
var plotArea = new XElement(c + "plotArea",
new XElement(c + "layout"));
// Create chart type group element
var groupElement = CreateChartGroupElement(chart, c);
if (groupElement is not null)
{
@@ -554,7 +543,6 @@ class XlsxWriter(Workbook sourceWorkbook)
group.Add(new XElement(c + "grouping", new XAttribute("val", grouping)));
}
// Add series
foreach (var series in chart.Series)
{
var ser = new XElement(c + "ser",
@@ -901,7 +889,6 @@ class XlsxWriter(Workbook sourceWorkbook)
var mediaMap = new Dictionary<string, string>();
var globalMediaIndex = 1;
// Process each sheet
for (var i = 0; i < sheets.Count; i++)
{
var sheet = sheets[i];
@@ -909,13 +896,11 @@ class XlsxWriter(Workbook sourceWorkbook)
var sheetName = $"sheet{sheetId}.xml";
var relId = $"rId{sheetId + 2}";
// Add sheet relationship (update Target to worksheets subdirectory)
workbookRelsElement.Add(new XElement(XName.Get("Relationship", pkgNs),
new XAttribute("Id", relId),
new XAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"),
new XAttribute("Target", $"worksheets/{sheetName}")));
// Save individual sheet
SaveSheet(archive, sheet, sheetName, sheetId, relId, styleTracker, sharedStrings, sharedStringsDoc, mediaMap, ref globalMediaIndex, ref globalTableIndex);
}
@@ -934,7 +919,6 @@ class XlsxWriter(Workbook sourceWorkbook)
new XAttribute("Target", "sharedStrings.xml")));
}
// Save workbook relationships
using var relsEntry = archive.CreateEntry("xl/_rels/workbook.xml.rels").Open();
workbookRels.Save(relsEntry);
}
@@ -950,25 +934,18 @@ class XlsxWriter(Workbook sourceWorkbook)
var sheetDoc = CreateSheetDocument(sheet, sheetId, relId);
var sheetData = sheetDoc.Root!.Element(XName.Get("sheetData", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"))!;
// Process all rows and cells
ProcessSheetData(sheet, sheetData, styleTracker, sharedStrings, sharedStringsDoc);
// Add merged cells
AddMergedCells(sheet, sheetDoc);
// Add auto filter
AddAutoFilter(sheet, sheetDoc);
// Add data validations
AddDataValidations(sheet, sheetDoc);
// Add sheet protection
AddSheetProtection(sheet, sheetDoc);
// Add hyperlinks
var hyperlinkRels = AddHyperlinks(sheet, sheetDoc);
// Track all sheet relationship entries
var sheetRelEntries = new List<(string Id, string Type, string Target, bool External)>();
foreach (var (id, url) in hyperlinkRels)
{
@@ -1337,14 +1314,12 @@ class XlsxWriter(Workbook sourceWorkbook)
var cellElement = new XElement(XName.Get("c", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"),
new XAttribute("r", new CellRef(row, col).ToString()));
// Add style reference if cell has formatting
if (HasCellFormatting(cell))
{
var styleId = GetOrCreateCellStyle(cell, styleTracker);
cellElement.Add(new XAttribute("s", styleId));
}
// Add cell value based on type
AddCellValue(cellElement, cell, sharedStrings, sharedStringsDoc);
return cellElement;
@@ -1497,7 +1472,6 @@ class XlsxWriter(Workbook sourceWorkbook)
var newId = 164 + styleTracker.NumberFormats.Count;
styleTracker.NumberFormats[formatCode] = newId;
// Create numFmt element
if (styleTracker.NumFmtsElement is null)
{
styleTracker.NumFmtsElement = new XElement(XName.Get("numFmts", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"),
@@ -1565,9 +1539,6 @@ class XlsxWriter(Workbook sourceWorkbook)
styleTracker.FillsElement.Attribute("count")!.Value = (styleTracker.FillStyles.Count + 2).ToString(CultureInfo.InvariantCulture);
}
/// <summary>
/// Creates a cell style element in the styles document.
/// </summary>
private void CreateCellStyleElement(Cell cell, int fontId, int fillId, int borderId, int numFmtId, StyleTracker styleTracker)
{
var xfElement = new XElement(XName.Get("xf", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"),
@@ -1615,9 +1586,6 @@ class XlsxWriter(Workbook sourceWorkbook)
styleTracker.CellXfsElement.Attribute("count")!.Value = (styleTracker.CellStyles.Count + 1).ToString(CultureInfo.InvariantCulture);
}
/// <summary>
/// Creates an alignment element for cell formatting.
/// </summary>
private static XElement CreateAlignmentElement(Cell cell)
{
var alignmentElement = new XElement(XName.Get("alignment", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
@@ -1783,7 +1751,6 @@ class XlsxWriter(Workbook sourceWorkbook)
new XAttribute("ref", sheet.AutoFilter.Range.Value.ToString()),
new XAttribute(XName.Get("uid", "http://schemas.microsoft.com/office/spreadsheetml/2014/revision"), uid));
// Process each filter and create filterColumn elements
foreach (var filter in sheet.Filters)
{
var filterColumn = CreateFilterColumn(filter, sheet.AutoFilter.Range.Value);
@@ -2185,7 +2152,6 @@ class XlsxWriter(Workbook sourceWorkbook)
var sheetsElement = workbook.Root!.Element(mainNs + "sheets")!;
// Add sheet references
for (var i = 0; i < sheets.Count; i++)
{
var sheet = sheets[i];

View File

@@ -5,9 +5,6 @@ using System;
using System.Collections.Generic;
namespace Radzen.Blazor.Spreadsheet;
/// <summary>
/// Specifies the direction of an autofill operation.
/// </summary>
enum AutofillDirection
{
Down,
@@ -16,22 +13,12 @@ enum AutofillDirection
Left
}
/// <summary>
/// Command that fills a target range by repeating a source range pattern.
/// Supports numeric series, date series, formula adjustment, and plain copy.
/// </summary>
class AutofillCommand : ICommand, IProtectedCommand
{
/// <inheritdoc/>
public SheetAction RequiredAction => SheetAction.EditCell;
/// <inheritdoc/>
public SpreadsheetFeature? Feature => SpreadsheetFeature.Autofill;
/// <summary>
/// Computes the autofill target range from the source selection and the cell the user dragged to.
/// Constrains to the dominant axis (vertical or horizontal).
/// </summary>
internal static RangeRef ComputeRange(RangeRef source, CellRef target)
{
var rowDelta = 0;
@@ -83,9 +70,6 @@ class AutofillCommand : ICommand, IProtectedCommand
return RangeRef.Invalid;
}
/// <summary>
/// Determines the fill direction by comparing the fill range to the source range.
/// </summary>
internal static AutofillDirection GetDirection(RangeRef source, RangeRef fill)
{
if (fill.End.Row > source.End.Row)
@@ -376,10 +360,6 @@ class AutofillCommand : ICommand, IProtectedCommand
}
}
/// <summary>
/// Attempts to detect an arithmetic numeric or date series in the source values.
/// Returns null if no series pattern is detected.
/// </summary>
private static SeriesInfo? DetectSeries(List<object?> sourceValues)
{
if (sourceValues.Count < 2)
@@ -464,9 +444,6 @@ class AutofillCommand : ICommand, IProtectedCommand
private abstract class SeriesInfo
{
/// <summary>
/// Gets the nth fill value. n is 1-based (1 = first cell past the source boundary).
/// </summary>
public abstract object GetValue(int n, AutofillDirection direction);
}

View File

@@ -86,11 +86,9 @@ public partial class CellMenu : ComponentBase
await base.SetParametersAsync(parameters);
// Check if any of the key parameters have changed
if (didRowChange || didColumnChange || didSheetChange)
{
InvalidateCache();
// Reinitialize the selected filter values
InitializeSelectedFilterValues();
}
}
@@ -209,8 +207,7 @@ public partial class CellMenu : ComponentBase
var totalItems = availableValues.Count + (showBlank ? 1 : 0);
var selectedCount = availableValues.Count(v => selectedFilterValues.Contains(v.Value));
// Add 1 to selected count if blank is selected
if (showBlank && selectedFilterValues.Contains(null))
{
selectedCount++;
@@ -314,8 +311,7 @@ public partial class CellMenu : ComponentBase
var showBlank = ShouldShowBlankOption();
var totalItems = availableValues.Count + (showBlank ? 1 : 0);
var selectedCount = availableValues.Count(v => selectedFilterValues.Contains(v.Value));
// Add 1 to selected count if blank is selected
if (showBlank && selectedFilterValues.Contains(null))
{
selectedCount++;
@@ -336,7 +332,6 @@ public partial class CellMenu : ComponentBase
if (rangeToUse != RangeRef.Invalid)
{
// Create a new range for the current column using the determined range
var columnRange = new RangeRef(
new CellRef(rangeToUse.Start.Row, Column),
new CellRef(rangeToUse.End.Row, Column)

View File

@@ -223,7 +223,6 @@ public partial class CellView : CellBase, IDisposable
private bool ShouldShowMenuForMergedCell()
{
// Check if the current cell is part of a merged range
var mergedRange = Worksheet.MergedCells.GetMergedRange(new CellRef(Row, Column));
if (mergedRange == RangeRef.Invalid)

View File

@@ -389,7 +389,6 @@ public partial class ChartOverlay : ComponentBase, IDisposable
chartBuilder.CloseComponent();
}
// Add axes for non-pie/donut charts
if (chart.ChartType != SpreadsheetChartType.Pie && chart.ChartType != SpreadsheetChartType.Donut)
{
chartBuilder.OpenComponent<RadzenCategoryAxis>(10000);
@@ -399,7 +398,6 @@ public partial class ChartOverlay : ComponentBase, IDisposable
chartBuilder.CloseComponent();
}
// Add legend if configured
if (chart.ShowLegend)
{
chartBuilder.OpenComponent<RadzenLegend>(10002);

View File

@@ -6,10 +6,8 @@ namespace Radzen.Blazor.Spreadsheet;
class ClearContentsCommand(Worksheet sheet, RangeRef range) : ICommand, IProtectedCommand
{
/// <inheritdoc/>
public SheetAction RequiredAction => SheetAction.EditCell;
/// <inheritdoc/>
public SpreadsheetFeature? Feature => SpreadsheetFeature.Editing;
private readonly Dictionary<CellRef, (object? value, string? formula)> snapshot = [];

View File

@@ -119,7 +119,6 @@ public abstract class HeaderBase : CellBase, IDisposable
return dirty;
}
/// <inheritdoc/>
void IDisposable.Dispose()
{
if (Worksheet is not null)

View File

@@ -84,7 +84,6 @@ public abstract class SheetSnapshotCommandBase : ICommand
}
}
// Restore backed-up cells
foreach (var ((row, column), (value, formula, format)) in backupCells)
{
var cell = sheet.Cells[row, column];

View File

@@ -117,7 +117,6 @@ public class SheetView
{
if (axis.Frozen > 0)
{
// Calculate position after frozen items
for (int index = 0; index < axis.Frozen; index++)
{
if (!axis.IsHidden(index))

View File

@@ -5,17 +5,8 @@ namespace Radzen.Blazor.Spreadsheet;
#nullable enable
/// <summary>
/// Visual presets for the built-in Excel table styles. Each preset captures the colors
/// and emphasis used by <see cref="Documents.Spreadsheet.Table.TableStyle"/> when rendering
/// inside <see cref="RadzenSpreadsheet"/>. Presets are generated for the full Excel
/// palette (Light1..21, Medium1..28, Dark1..11) so every named style produces a
/// distinct visual output. Colors approximate the Office default theme; precise
/// Excel theming would require reading <c>theme1.xml</c> from the package.
/// </summary>
internal static class TableStylePresets
{
/// <summary>Color set for one named table style.</summary>
internal sealed record Preset(
string? HeaderBackground,
string? HeaderColor,
@@ -62,7 +53,6 @@ internal static class TableStylePresets
private static readonly Dictionary<string, Preset> presets = BuildAll();
/// <summary>Looks up a preset by name; falls back to a sensible default.</summary>
internal static Preset Get(string? name)
{
if (string.IsNullOrEmpty(name))

View File

@@ -20,14 +20,12 @@
{
if (Worksheet is null) return false;
// Check if we're in a data table
var dataTable = GetCurrentTable();
if (dataTable is not null)
{
return dataTable.ShowFilterButton;
}
// Check if sheet has auto filter
return Worksheet.AutoFilter.Range is not null;
}
}

View File

@@ -99,7 +99,6 @@ public abstract class FormatToggleToolBase : ComponentBase, IDisposable
StateHasChanged();
}
/// <inheritdoc/>
void IDisposable.Dispose()
{
if (Worksheet?.Selection is not null)

View File

@@ -59,7 +59,6 @@ public abstract class SpreadsheetToolBase : ComponentBase, IDisposable
StateHasChanged();
}
/// <inheritdoc/>
void IDisposable.Dispose()
{
if (Worksheet?.Selection is not null)

View File

@@ -562,7 +562,6 @@ public partial class VirtualGrid : ComponentBase, IAsyncDisposable, IVirtualGrid
foreach (var range in visibleMergedCells)
{
// Adjust the range to start from the first visible row and column
var adjustedRange = AdjustRangeForHiddenRowsAndColumns(range);
// Skip if the entire range is hidden