diff --git a/Radzen.Blazor/Spreadsheet/ColumnHeader.razor b/Radzen.Blazor/Spreadsheet/ColumnHeader.razor index 7c2de6eff..3c0af0034 100644 --- a/Radzen.Blazor/Spreadsheet/ColumnHeader.razor +++ b/Radzen.Blazor/Spreadsheet/ColumnHeader.razor @@ -1,6 +1,6 @@ @using Radzen.Documents.Spreadsheet @using Microsoft.AspNetCore.Components.Web -@inherits CellBase +@inherits HeaderBase
@ColumnRef.ToString(Column)
diff --git a/Radzen.Blazor/Spreadsheet/ColumnHeader.razor.cs b/Radzen.Blazor/Spreadsheet/ColumnHeader.razor.cs index 29617ef28..565d1102b 100644 --- a/Radzen.Blazor/Spreadsheet/ColumnHeader.razor.cs +++ b/Radzen.Blazor/Spreadsheet/ColumnHeader.razor.cs @@ -1,7 +1,6 @@ +using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Components; using Radzen.Blazor.Rendering; -using System; -using System.Threading.Tasks; using Radzen.Documents.Spreadsheet; namespace Radzen.Blazor.Spreadsheet; @@ -10,7 +9,7 @@ namespace Radzen.Blazor.Spreadsheet; /// /// Renders a column header in a spreadsheet. /// -public partial class ColumnHeader : CellBase, IDisposable +public partial class ColumnHeader : HeaderBase { /// /// Gets or sets the column index of the column header. @@ -18,95 +17,26 @@ public partial class ColumnHeader : CellBase, IDisposable [Parameter] public int Column { get; set; } - /// - /// Gets or sets the sheet that contains the column header. - /// - [Parameter] - public Worksheet? Worksheet { get; set; } + /// + protected override int Index => Column; - private bool active; - private bool selected; + /// + protected override string IndexParameterName => nameof(Column); + + /// + [SuppressMessage("Design", "CA1062", Justification = "Base class guarantees non-null.")] + protected override bool CheckIsActive(Selection selection) => selection.IsActive(new ColumnRef(Column)); + + /// + [SuppressMessage("Design", "CA1062", Justification = "Base class guarantees non-null.")] + protected override bool CheckIsSelected(Selection selection) => selection.IsSelected(new ColumnRef(Column)); private string Class => ClassList.Create("rz-spreadsheet-column-header") .Add("rz-spreadsheet-frozen-row", FrozenState.HasFlag(FrozenState.Row)) .Add("rz-spreadsheet-frozen-column", FrozenState.HasFlag(FrozenState.Column)) - .Add("rz-spreadsheet-header-active", active) - .Add("rz-spreadsheet-header-selected", selected) + .Add("rz-spreadsheet-header-active", Active) + .Add("rz-spreadsheet-header-selected", Selected) .ToString(); private string ResizeHandleStyle => $"left: {Rect.Right.ToPx()}; top: {Rect.Top.ToPx()}; height: {Rect.Height.ToPx()};"; - - - /// - protected override void OnInitialized() - { - UpdateState(); - } - - /// - public override async Task SetParametersAsync(ParameterView parameters) - { - if (Worksheet != null) - { - Worksheet.Selection.Changed -= OnSelectionChanged; - } - - var didColumnChange = parameters.TryGetValue(nameof(Column), out var column) && Column != column; - - await base.SetParametersAsync(parameters); - - if (Worksheet != null) - { - Worksheet.Selection.Changed += OnSelectionChanged; - } - - if (didColumnChange) - { - UpdateState(); - } - } - - private void OnSelectionChanged() - { - var dirty = UpdateState(); - - if (dirty) - { - StateHasChanged(); - } - } - - private bool UpdateState() - { - var dirty = false; - - if (Worksheet is not null) - { - var address = new ColumnRef(Column); - - if (Worksheet.Selection.IsActive(address) != active) - { - active = !active; - - dirty = true; - } - - if (Worksheet.Selection.IsSelected(address) != selected) - { - selected = !selected; - - dirty = true; - } - } - - return dirty; - } - - void IDisposable.Dispose() - { - if (Worksheet != null) - { - Worksheet.Selection.Changed -= OnSelectionChanged; - } - } -} \ No newline at end of file +} diff --git a/Radzen.Blazor/Spreadsheet/HeaderBase.cs b/Radzen.Blazor/Spreadsheet/HeaderBase.cs new file mode 100644 index 000000000..35480ac07 --- /dev/null +++ b/Radzen.Blazor/Spreadsheet/HeaderBase.cs @@ -0,0 +1,130 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Radzen.Blazor.Rendering; + +using Radzen.Documents.Spreadsheet; +namespace Radzen.Blazor.Spreadsheet; + +#nullable enable + +/// +/// Base class for row and column header components. Manages selection state tracking, +/// event subscription lifecycle, and CSS class generation. +/// Subclasses provide the axis-specific index, address creation, and CSS class name. +/// +public abstract class HeaderBase : CellBase, IDisposable +{ + /// + /// Gets or sets the worksheet that contains this header. + /// + [Parameter] + public Worksheet? Worksheet { get; set; } + + private bool active; + + /// + /// Gets whether the header is in the active selection range. + /// + protected bool Active => active; + + private bool selected; + + /// + /// Gets whether the header's entire row/column is selected. + /// + protected bool Selected => selected; + + /// + /// Gets the axis index (row or column) for this header. + /// + protected abstract int Index { get; } + + /// + /// Gets the parameter name to watch for changes (e.g. "Row" or "Column"). + /// + protected abstract string IndexParameterName { get; } + + /// + /// Returns whether the selection is active for this header's axis position. + /// Called only after validating that is non-null. + /// + protected abstract bool CheckIsActive(Selection selection); + + /// + /// Returns whether the selection covers this header's entire row/column. + /// Called only after validating that is non-null. + /// + protected abstract bool CheckIsSelected(Selection selection); + + /// + protected override void OnInitialized() + { + UpdateState(); + } + + /// + public override async Task SetParametersAsync(ParameterView parameters) + { + if (Worksheet != null) + { + Worksheet.Selection.Changed -= OnSelectionChanged; + } + + var didIndexChange = parameters.TryGetValue(IndexParameterName, out var index) && Index != index; + + await base.SetParametersAsync(parameters); + + if (Worksheet != null) + { + Worksheet.Selection.Changed += OnSelectionChanged; + } + + if (didIndexChange) + { + UpdateState(); + } + } + + private void OnSelectionChanged() + { + if (UpdateState()) + { + StateHasChanged(); + } + } + + private bool UpdateState() + { + var dirty = false; + + if (Worksheet is not null) + { + var selection = Worksheet.Selection; + + if (CheckIsActive(selection) != active) + { + active = !active; + dirty = true; + } + + if (CheckIsSelected(selection) != selected) + { + selected = !selected; + dirty = true; + } + } + + return dirty; + } + + /// + void IDisposable.Dispose() + { + if (Worksheet != null) + { + Worksheet.Selection.Changed -= OnSelectionChanged; + } + } +} diff --git a/Radzen.Blazor/Spreadsheet/RowHeader.razor b/Radzen.Blazor/Spreadsheet/RowHeader.razor index 075abdb0a..2e001d744 100644 --- a/Radzen.Blazor/Spreadsheet/RowHeader.razor +++ b/Radzen.Blazor/Spreadsheet/RowHeader.razor @@ -1,6 +1,6 @@ @using Radzen.Documents.Spreadsheet @using Microsoft.AspNetCore.Components.Web -@inherits CellBase +@inherits HeaderBase
@(Row + 1)
diff --git a/Radzen.Blazor/Spreadsheet/RowHeader.razor.cs b/Radzen.Blazor/Spreadsheet/RowHeader.razor.cs index 09d9d34fc..e8e134480 100644 --- a/Radzen.Blazor/Spreadsheet/RowHeader.razor.cs +++ b/Radzen.Blazor/Spreadsheet/RowHeader.razor.cs @@ -1,8 +1,6 @@ - +using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Components; using Radzen.Blazor.Rendering; -using System; -using System.Threading.Tasks; using Radzen.Documents.Spreadsheet; namespace Radzen.Blazor.Spreadsheet; @@ -12,7 +10,7 @@ namespace Radzen.Blazor.Spreadsheet; /// /// Renders a row header in a spreadsheet. /// -public partial class RowHeader : CellBase, IDisposable +public partial class RowHeader : HeaderBase { /// /// Gets or sets the row index for the row header. @@ -20,93 +18,26 @@ public partial class RowHeader : CellBase, IDisposable [Parameter] public int Row { get; set; } - /// - /// Gets or sets the sheet that contains the row header. - /// - [Parameter] - public Worksheet? Worksheet { get; set; } + /// + protected override int Index => Row; - private bool active; - private bool selected; + /// + protected override string IndexParameterName => nameof(Row); + + /// + [SuppressMessage("Design", "CA1062", Justification = "Base class guarantees non-null.")] + protected override bool CheckIsActive(Selection selection) => selection.IsActive(new RowRef(Row)); + + /// + [SuppressMessage("Design", "CA1062", Justification = "Base class guarantees non-null.")] + protected override bool CheckIsSelected(Selection selection) => selection.IsSelected(new RowRef(Row)); private string Class => ClassList.Create("rz-spreadsheet-row-header") .Add("rz-spreadsheet-frozen-row", FrozenState.HasFlag(FrozenState.Row)) .Add("rz-spreadsheet-frozen-column", FrozenState.HasFlag(FrozenState.Column)) - .Add("rz-spreadsheet-header-active", active) - .Add("rz-spreadsheet-header-selected", selected) + .Add("rz-spreadsheet-header-active", Active) + .Add("rz-spreadsheet-header-selected", Selected) .ToString(); private string ResizeHandleStyle => $"top: {Rect.Bottom.ToPx()}; left: {Rect.Left.ToPx()}; width: {Rect.Width.ToPx()};"; - - /// - protected override void OnInitialized() - { - UpdateState(); - } - - /// - public override async Task SetParametersAsync(ParameterView parameters) - { - if (Worksheet != null) - { - Worksheet.Selection.Changed -= OnSelectionChanged; - } - var didRowChange = parameters.TryGetValue(nameof(Row), out var row) && Row != row; - - await base.SetParametersAsync(parameters); - - if (Worksheet != null) - { - Worksheet.Selection.Changed += OnSelectionChanged; - } - - if (didRowChange) - { - UpdateState(); - } - } - - private void OnSelectionChanged() - { - var dirty = UpdateState(); - - if (dirty) - { - StateHasChanged(); - } - } - - private bool UpdateState() - { - var dirty = false; - - if (Worksheet is not null) - { - var address = new RowRef(Row); - - if (Worksheet.Selection.IsActive(address) != active) - { - active = !active; - - dirty = true; - } - - if (Worksheet.Selection.IsSelected(address) != selected) - { - selected = !selected; - - dirty = true; - } - } - - return dirty; - } - - void IDisposable.Dispose() - { - if (Worksheet != null) - { - Worksheet.Selection.Changed -= OnSelectionChanged; - } - } -} \ No newline at end of file +}