mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
The autofilter dropdown for column X is supposed to list distinct values visible under filters on OTHER columns (Excel parity). The old implementation used filter.Range.Contains(row, Column) to decide which filters target the current column — but filters created from FilterDialog use the full table / auto-filter range, so Range.Contains returns true for EVERY filter at any cell in that range. Result: ALL filters were treated as 'for this column' and the dropdown ignored every cross-column filter. Introduce FilterColumnVisitor (extends FilterCriterionVisitorBase) that extracts the target column(s) via the existing visitor pattern. The new IsRowHiddenByOtherColumnFilter helper skips filters that target only the current column and re-evaluates the criterion via Matches(worksheet, row). Adds 4 tests covering: no filters, only-current-column filter ignored, other-column filter applied, two-column cross-visibility. Also covers: - TableDesignPanel TotalsOptions cached in OnInitialized (was allocating an object[] per render). - CellMenu HasFilterApplied collapsed from a foreach to a one-liner LINQ. - CellMenuItem.razor: Click.InvokeAsync(null) -> Click.InvokeAsync().
238 lines
10 KiB
Plaintext
238 lines
10 KiB
Plaintext
@using System.Collections.Generic
|
|
@using System.Linq
|
|
@using Radzen.Blazor
|
|
@using Radzen.Documents.Spreadsheet
|
|
@implements IDisposable
|
|
@inject Localizer Localizer
|
|
|
|
@if (CurrentTable is not null)
|
|
{
|
|
<RadzenStack Orientation="Orientation.Horizontal" Gap="0.75rem" AlignItems="AlignItems.Center"
|
|
class="rz-spreadsheet-table-design">
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignName)) Component="tableNameInput" />
|
|
<RadzenTextBox @bind-Value=@tableName Name="tableNameInput"
|
|
Change=@(_ => CommitName()) InputSize="InputSize.Small" Style="width:160px" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignStyle)) Component="tableStyleDD" />
|
|
<RadzenDropDown TValue="string" Data=@styleOptions
|
|
Value=@(CurrentTable.TableStyle ?? "")
|
|
Change=@(v => CommitStyle(v as string))
|
|
Name="tableStyleDD" InputSize="InputSize.Small" Style="width:200px" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.75rem">
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenCheckBox Value=@CurrentTable.ShowHeaderRow
|
|
Change=@(v => Toggle(t => t.ShowHeaderRow = (bool)v)) TValue="bool"
|
|
Name="hdrChk" />
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignHeader)) Component="hdrChk" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenCheckBox Value=@CurrentTable.ShowTotals
|
|
Change=@(v => Toggle(t => t.ShowTotals = (bool)v)) TValue="bool"
|
|
Name="totChk" />
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignTotals)) Component="totChk" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenCheckBox Value=@CurrentTable.ShowFilterButton
|
|
Change=@(v => Toggle(t => t.ShowFilterButton = (bool)v)) TValue="bool"
|
|
Disabled=@(!CurrentTable.ShowHeaderRow)
|
|
Name="fltChk" />
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignFilter)) Component="fltChk" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenCheckBox Value=@CurrentTable.ShowBandedRows
|
|
Change=@(v => Toggle(t => t.ShowBandedRows = (bool)v)) TValue="bool"
|
|
Name="bndRowChk" />
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignBandedRows)) Component="bndRowChk" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenCheckBox Value=@CurrentTable.ShowBandedColumns
|
|
Change=@(v => Toggle(t => t.ShowBandedColumns = (bool)v)) TValue="bool"
|
|
Name="bndColChk" />
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignBandedColumns)) Component="bndColChk" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenCheckBox Value=@CurrentTable.HighlightFirstColumn
|
|
Change=@(v => Toggle(t => t.HighlightFirstColumn = (bool)v)) TValue="bool"
|
|
Name="firstChk" />
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignFirstColumn)) Component="firstChk" />
|
|
</RadzenStack>
|
|
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenCheckBox Value=@CurrentTable.HighlightLastColumn
|
|
Change=@(v => Toggle(t => t.HighlightLastColumn = (bool)v)) TValue="bool"
|
|
Name="lastChk" />
|
|
<RadzenLabel Text=@L(nameof(RadzenStrings.Spreadsheet_TableDesignLastColumn)) Component="lastChk" />
|
|
</RadzenStack>
|
|
</RadzenStack>
|
|
|
|
@if (TotalsColumn is { } totalsCol)
|
|
{
|
|
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.25rem">
|
|
<RadzenLabel Text=@string.Format(System.Globalization.CultureInfo.CurrentCulture, L(nameof(RadzenStrings.Spreadsheet_TableDesignTotalsForColumn)), totalsCol.Name) />
|
|
<RadzenDropDown TValue="TotalsCalculation" Data=@TotalsOptions
|
|
TextProperty="@nameof(TotalsOption.Text)" ValueProperty="@nameof(TotalsOption.Value)"
|
|
Value=@totalsCol.TotalsCalculation
|
|
Change=@(v => CommitTotals(totalsCol, (TotalsCalculation)v))
|
|
InputSize="InputSize.Small" Style="width:180px" />
|
|
</RadzenStack>
|
|
}
|
|
|
|
<span style="flex:1"></span>
|
|
|
|
<RadzenButton Icon="grid_off" Text=@L(nameof(RadzenStrings.Spreadsheet_ConvertTableToRange))
|
|
ButtonStyle="ButtonStyle.Base" Variant="Variant.Flat" Size="ButtonSize.Small"
|
|
Click=@OnConvertToRange />
|
|
</RadzenStack>
|
|
}
|
|
|
|
@code {
|
|
#nullable enable
|
|
|
|
[Parameter] public Worksheet? Worksheet { get; set; }
|
|
[CascadingParameter] public ISpreadsheet? Spreadsheet { get; set; }
|
|
|
|
private string L(string key) => Localizer.Get(key, System.Globalization.CultureInfo.CurrentUICulture);
|
|
|
|
private Table? CurrentTable
|
|
{
|
|
get
|
|
{
|
|
if (Worksheet is null) return null;
|
|
var sel = Worksheet.Selection.Cell;
|
|
if (sel == CellRef.Invalid) return null;
|
|
return Worksheet.GetTableContaining(sel.Row, sel.Column);
|
|
}
|
|
}
|
|
|
|
private string tableName = "";
|
|
|
|
private TableColumn? TotalsColumn
|
|
{
|
|
get
|
|
{
|
|
var t = CurrentTable;
|
|
if (t is null || !t.ShowTotals || Worksheet is null) return null;
|
|
var sel = Worksheet.Selection.Cell;
|
|
if (sel == CellRef.Invalid) return null;
|
|
var totals = t.TotalsRowRange;
|
|
if (totals is null || !totals.Value.Contains(sel.Row, sel.Column)) return null;
|
|
var idx = sel.Column - t.Range.Start.Column;
|
|
return idx >= 0 && idx < t.Columns.Count ? t.Columns[idx] : null;
|
|
}
|
|
}
|
|
|
|
private sealed record TotalsOption(string Text, TotalsCalculation Value);
|
|
private TotalsOption[] TotalsOptions = [];
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
TotalsOptions =
|
|
[
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsNone)), TotalsCalculation.None),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsSum)), TotalsCalculation.Sum),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsAverage)), TotalsCalculation.Average),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsCount)), TotalsCalculation.Count),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsCountNumbers)), TotalsCalculation.CountNumbers),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsMin)), TotalsCalculation.Min),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsMax)), TotalsCalculation.Max),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsStdDev)), TotalsCalculation.StdDev),
|
|
new(L(nameof(RadzenStrings.Spreadsheet_TotalsVar)), TotalsCalculation.Var),
|
|
];
|
|
}
|
|
|
|
private void CommitTotals(TableColumn col, TotalsCalculation calc)
|
|
{
|
|
col.TotalsCalculation = calc;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private static readonly List<string> styleOptions = BuildStyleOptions();
|
|
|
|
private static List<string> BuildStyleOptions()
|
|
{
|
|
var list = new List<string> { "" };
|
|
for (var i = 1; i <= 21; i++) list.Add($"TableStyleLight{i}");
|
|
for (var i = 1; i <= 28; i++) list.Add($"TableStyleMedium{i}");
|
|
for (var i = 1; i <= 11; i++) list.Add($"TableStyleDark{i}");
|
|
return list;
|
|
}
|
|
|
|
public override async Task SetParametersAsync(ParameterView parameters)
|
|
{
|
|
if (Worksheet?.Selection is not null)
|
|
{
|
|
Worksheet.Selection.Changed -= OnSelectionChanged;
|
|
}
|
|
|
|
await base.SetParametersAsync(parameters);
|
|
|
|
if (Worksheet?.Selection is not null)
|
|
{
|
|
Worksheet.Selection.Changed += OnSelectionChanged;
|
|
}
|
|
|
|
SyncFromTable();
|
|
}
|
|
|
|
private void OnSelectionChanged()
|
|
{
|
|
SyncFromTable();
|
|
StateHasChanged();
|
|
}
|
|
|
|
private void SyncFromTable()
|
|
{
|
|
tableName = CurrentTable?.Name ?? "";
|
|
}
|
|
|
|
private void CommitName()
|
|
{
|
|
if (CurrentTable is null) return;
|
|
var trimmed = tableName.Trim();
|
|
if (string.IsNullOrEmpty(trimmed) || trimmed == CurrentTable.Name) return;
|
|
try { CurrentTable.Name = trimmed; }
|
|
catch (System.ArgumentException) { tableName = CurrentTable.Name; }
|
|
StateHasChanged();
|
|
}
|
|
|
|
private void CommitStyle(string? value)
|
|
{
|
|
if (CurrentTable is null) return;
|
|
CurrentTable.TableStyle = string.IsNullOrEmpty(value) ? null : value;
|
|
StateHasChanged();
|
|
}
|
|
|
|
private void Toggle(System.Action<Table> mutator)
|
|
{
|
|
if (CurrentTable is null) return;
|
|
mutator(CurrentTable);
|
|
StateHasChanged();
|
|
}
|
|
|
|
private async Task OnConvertToRange()
|
|
{
|
|
if (Worksheet is null || CurrentTable is null || Spreadsheet is null) return;
|
|
await Spreadsheet.ExecuteAsync(new RemoveTableCommand(Worksheet, CurrentTable));
|
|
StateHasChanged();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Worksheet?.Selection is not null)
|
|
{
|
|
Worksheet.Selection.Changed -= OnSelectionChanged;
|
|
}
|
|
}
|
|
}
|