diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnResizing.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnResizing.razor index 0ff4b8f4a83..ba47a14c81e 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnResizing.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesColumnResizing.razor @@ -1,4 +1,4 @@ -@page "/table/column/resizing" +@page "/table/column/resizing" @inject IStringLocalizer NavMenuLocalizer @inject IStringLocalizer Localizer @inject IStringLocalizer FooLocalizer diff --git a/src/BootstrapBlazor/Components/Table/ITable.cs b/src/BootstrapBlazor/Components/Table/ITable.cs index f9288db74e5..a963524dcdf 100644 --- a/src/BootstrapBlazor/Components/Table/ITable.cs +++ b/src/BootstrapBlazor/Components/Table/ITable.cs @@ -15,7 +15,7 @@ public interface ITable : IColumnCollection /// 获得 ITable 实例配置的可见列集合 /// Gets visible columns collection configured in ITable instance /// - IEnumerable GetVisibleColumns(); + List GetVisibleColumns(); /// /// 获得 过滤条件集合 diff --git a/src/BootstrapBlazor/Components/Table/Table.razor b/src/BootstrapBlazor/Components/Table/Table.razor index 76000118321..e761d69a310 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor +++ b/src/BootstrapBlazor/Components/Table/Table.razor @@ -20,24 +20,26 @@ } else { - BuildTableColumns(); - RebuildVisibleColumnsCache(); - if (ShowSearch && SearchMode == SearchMode.Top) - { - @RenderSearch - } + + @{ + RebuildTableColumns(); + } - if (ShowToolbar) - { - @RenderToolbar - } + @if (ShowSearch && SearchMode == SearchMode.Top) + { + @RenderSearch + } - if (ShowTopPagination && IsPagination) - { - @RenderPagination - } + @if (ShowToolbar) + { + @RenderToolbar + } + + @if (ShowTopPagination && IsPagination) + { + @RenderPagination + } -
@if (ActiveRenderMode == TableRenderMode.Table) { @@ -303,7 +305,7 @@ { var fieldName = col.GetFieldName(); var displayName = col.GetDisplayName(); - diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs index ebaab1c52a0..8c9774f0a1d 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs @@ -168,21 +168,26 @@ private async Task OnToggleColumnVisible(TableColumnState item, bool visible) column.Visible = visible; } - if (column.Visible) + if (!column.Visible) { - // 重新计算表格宽度 - if (column.Width.HasValue) - { - tableWidth += column.Visible ? column.Width.Value : 0; - } - else - { - useTableWidth = false; - } + continue; + } + + // 重新计算表格宽度 + if (column.Width.HasValue) + { + tableWidth += column.Width.Value; + } + else + { + // 未设置列宽表格自适应 + useTableWidth = false; } } _tableColumnStateCache.TableWidth = useTableWidth ? tableWidth : 0; + + UpdateTableWidth(); } // 触发 OnColumnVisibleChanged 回调 diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Sort.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Sort.cs index d45e5f28c86..ea6ca48e781 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Sort.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Sort.cs @@ -194,7 +194,7 @@ private int MultipleSelectColumnLeft() /// protected string? GetFixedCellClassString(ITableColumn col, string? cellClass = null) => CssBuilder.Default(cellClass) .AddClass("fixed", col.Fixed) - .AddClass("fixed-right", col.Fixed && IsTail(col)) + .AddClass("fixed-right", col.Fixed && IsFixRight(col)) .AddClass("fr", IsLastColumn(col)) .AddClass("fl", IsFirstColumn(col)) .Build(); @@ -243,10 +243,11 @@ private int MultipleSelectColumnLeft() private bool IsLastColumn(ITableColumn col) => LastFixedColumnCache.GetOrAdd(col, col => { var ret = false; - if (col.Fixed && !IsTail(col)) + if (col.Fixed && !IsFixRight(col)) { - var index = Columns.IndexOf(col) + 1; - ret = index < Columns.Count && Columns[index].Fixed == false; + var columns = GetVisibleColumns(); + var index = columns.IndexOf(col) + 1; + ret = index < columns.Count && columns[index].Fixed == false; } return ret; }); @@ -258,12 +259,13 @@ private bool IsLastColumn(ITableColumn col) => LastFixedColumnCache.GetOrAdd(col private bool IsFirstColumn(ITableColumn col) => FirstFixedColumnCache.GetOrAdd(col, col => { var ret = false; - if (col.Fixed && IsTail(col)) + if (col.Fixed && IsFixRight(col)) { - var index = Columns.IndexOf(col) - 1; - if (index > 0) + var columns = GetVisibleColumns(); + var index = columns.IndexOf(col) - 1; + if (index >= 0) { - ret = !Columns[index].Fixed; + ret = !columns[index].Fixed; } } return ret; @@ -310,11 +312,15 @@ private int CalcMargin() return margin; } - private bool IsTail(ITableColumn col) + private bool IsFixRight(ITableColumn col) { - var middle = Math.Floor(GetVisibleColumns().Count() * 1.0 / 2); - var index = Columns.IndexOf(col); - return middle < index; + // 获得所有可见列 + var columns = GetVisibleColumns(); + + // 获得当前列索引 + var index = columns.IndexOf(col); + + return !columns.Take(index).All(i => i.Fixed); } /// @@ -344,14 +350,14 @@ string GetFixedHeaderStyleString() => IsFixedHeader string? ret = null; if (col.Fixed) { - ret = IsTail(col) ? GetRightStyle(col, margin) : GetLeftStyle(col); + ret = IsFixRight(col) ? GetRightStyle(col, margin) : GetLeftStyle(col); } return ret; } private string? GetLeftStyle(ITableColumn col) { - var columns = GetVisibleColumns().ToList(); + var columns = GetVisibleColumns(); var defaultWidth = 200; var width = 0; var start = 0; @@ -378,25 +384,22 @@ string GetFixedHeaderStyleString() => IsFixedHeader private string? GetRightStyle(ITableColumn col, int margin) { - var columns = GetVisibleColumns().ToList(); - var defaultWidth = 200; + var columns = GetVisibleColumns(); + var defaultWidth = DefaultFixedColumnWidth; var width = 0; var index = columns.IndexOf(col); // after - while (index + 1 < columns.Count) + for (var i = index + 1; i < columns.Count; i++) { - var column = columns[index++]; + var column = columns[i]; width += column.Width ?? defaultWidth; } if (ShowExtendButtons && FixedExtendButtonsColumn) { width += ExtendButtonColumnWidth; } - - // 如果是固定表头时增加滚动条位置 - // Add scroll bar position if it is fixed header - if (IsFixedHeader && (index + 1) == columns.Count) + if (IsFixedHeader) { width += margin; } diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs index b814a3dacf1..0e90f355d28 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs @@ -552,7 +552,7 @@ public Func? ShowDeleteButtonCallback /// 获得当前可见列集合 /// Get Visible Columns Collection /// - public IEnumerable GetVisibleColumns() => _visibleColumnsCache; + public List GetVisibleColumns() => _visibleColumnsCache; private void RebuildVisibleColumnsCache() { diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.cs b/src/BootstrapBlazor/Components/Table/Table.razor.cs index d0e132d1805..385fa7a2f37 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web.Virtualization; using System.Reflection; -using System.Text.Json; namespace BootstrapBlazor.Components; @@ -516,7 +515,7 @@ private string GetSortTooltip(ITableColumn col) => SortName != col.GetFieldName( [NotNull] private ILookupService? InjectLookupService { get; set; } - private TableColumnLocalstorageStatus _tableColumnStateCache = new(); + private TableColumnClientStatus _tableColumnStateCache = new(); private BreakPoint _screenSize; private string? _clientTableName; private bool _lastIsPopoverToolbarDropdownButtonValue; @@ -1122,18 +1121,8 @@ protected override async Task OnAfterRenderAsync(bool firstRender) // 读取浏览器持久化列状态配置 await ReloadColumnStatesFromBrowserAsync(); - // 列排序回调方法 - if (ColumnOrderCallback != null) - { - Columns.Clear(); - Columns.AddRange(ColumnOrderCallback(Columns)); - } - - // 调用列创建回调方法 - if (OnColumnCreating != null) - { - await OnColumnCreating(Columns); - } + // 构建列信息 + await BuildTableColumns(); // 调用查询方法渲染 UI await QueryAsync(true, 1, false, true, IsAutoQueryFirstRender); @@ -1285,33 +1274,7 @@ private void OnParameterCheckChanged() } } - private async Task ReloadColumnStatesFromBrowserAsync() - { - // 未开启客户端持久化功能直接返回 - if (string.IsNullOrEmpty(ClientTableName)) - { - return; - } - - var state = await InvokeAsync("getColumnStates", ClientTableName); - if (state == null) - { - state = new(); - - // 开启客户端持久化后未设置列状态的列默认使用组件参数值 - state.Columns.AddRange(Columns.Where(i => !i.GetIgnore()).Select(i => new TableColumnState() - { - Name = i.GetFieldName(), - Visible = i.GetVisible(), - DisplayName = i.GetDisplayName(), - Width = i.Width - })); - } - - _tableColumnStateCache = state; - } - - private void BuildTableColumns() + private List GetTableColumns() { // 动态列模式 var cols = new List(); @@ -1328,27 +1291,96 @@ private void BuildTableColumns() cols.AddRange(Columns); } + if (ColumnOrderCallback != null) + { + cols = [.. ColumnOrderCallback(cols)]; + } + + return cols; + } + + private async Task TriggerColumnCreating(List cols) + { + if (OnColumnCreating != null) + { + await OnColumnCreating(cols); + } + } + + private async Task BuildTableColumns() + { + // 构建列信息 + var cols = GetTableColumns(); + + // 触发列创建事件 + await TriggerColumnCreating(cols); + + Columns.Clear(); + Columns.AddRange(cols.OrderFunc()); + + // set default sortName + var col = Columns.Find(i => i is { Sortable: true, DefaultSort: true }); + if (col != null) + { + SortName = col.GetFieldName(); + SortOrder = col.DefaultSortOrder; + } + // 加载客户端持久化列状态 - RebuildTableColumnFromCache(cols); + RebuildTableColumnFromCache(); + } + + private void RebuildTableColumns() + { + // 构建列信息 + var cols = GetTableColumns(); Columns.Clear(); Columns.AddRange(cols.OrderFunc()); // set default sortName - var column = Columns.Find(i => i is { Sortable: true, DefaultSort: true }); - if (column != null) + var col = Columns.Find(i => i is { Sortable: true, DefaultSort: true }); + if (col != null) + { + SortName = col.GetFieldName(); + SortOrder = col.DefaultSortOrder; + } + + // 加载客户端持久化列状态 + RebuildTableColumnFromCache(); + } + + private async Task ReloadColumnStatesFromBrowserAsync() + { + // 未开启客户端持久化功能直接返回 + if (string.IsNullOrEmpty(ClientTableName)) { - SortName = column.GetFieldName(); - SortOrder = column.DefaultSortOrder; + return; } + + var state = await InvokeAsync("getColumnStates", ClientTableName); + if (state == null) + { + state = new(); + + // 开启客户端持久化后未设置列状态的列默认使用组件参数值 + state.Columns.AddRange(Columns.Where(i => !i.GetIgnore()).Select(i => new TableColumnState() + { + Name = i.GetFieldName(), + Visible = i.GetVisible(), + DisplayName = i.GetDisplayName(), + Width = i.Width + })); + } + + _tableColumnStateCache = state; } - private void RebuildTableColumnFromCache(List cols) + private void RebuildTableColumnFromCache() { - if (!string.IsNullOrEmpty(ClientTableName)) + if (_tableColumnStateCache.Columns.Count != 0) { - // 提高性能避免循环 - foreach (var col in cols) + foreach (var col in Columns) { var fieldName = col.GetFieldName(); @@ -1358,7 +1390,6 @@ private void RebuildTableColumnFromCache(List cols) { col.Width = column.Width; col.Visible = column.Visible; - column.DisplayName = col.GetDisplayName(); } } @@ -1366,7 +1397,9 @@ private void RebuildTableColumnFromCache(List cols) // 设置可见列顺序 _columnVisibleItems.Clear(); - _columnVisibleItems.AddRange(GetColumnVisibleItems(cols)); + _columnVisibleItems.AddRange(GetColumnVisibleItems(Columns)); + + RebuildVisibleColumnsCache(); } private List GetColumnVisibleItems(List cols) @@ -1374,7 +1407,7 @@ private List GetColumnVisibleItems(List cols) // 开启客户端持久化后未设置列状态的列默认使用组件参数值 return _tableColumnStateCache.Columns.Count != 0 ? _tableColumnStateCache.Columns - : [.. cols.Where(i => !i.GetIgnore()).Select(i => new TableColumnState() + : [.. cols.Where(i => !i.GetIgnore() && i.ShownWithBreakPoint <= _screenSize).Select(i => new TableColumnState() { Name = i.GetFieldName(), Visible = i.GetVisible(), @@ -1391,6 +1424,7 @@ private async Task OnTableRenderAsync(bool firstRender) TableName = ClientTableName, DragColumnCallback = nameof(DragColumnCallback), FitColumnWidthIncludeHeader, + AutoFitColumnWidthCallback = nameof(AutoFitColumnWidthCallback), ResizeColumnCallback = nameof(ResizeColumnCallback), ColumnMinWidth = ColumnMinWidth ?? Options.CurrentValue.TableSettings.ColumnMinWidth, VisibleColumns = string.IsNullOrEmpty(ClientTableName) ? null : _columnVisibleItems, @@ -1452,21 +1486,19 @@ private async Task OnTableRenderAsync(bool firstRender) /// public void ResetVisibleColumns(IEnumerable columns) { - // https://github.com/dotnetcore/BootstrapBlazor/issues/6823 foreach (var col in columns) { - // 使用 for + break 性能更好 - for (var index = 0; index < _columnVisibleItems.Count; index++) + var column = Columns.Find(i => i.GetFieldName() == col.Name); + if (column != null) { - var item = _columnVisibleItems[index]; - if (item.Name == col.Name) - { - item.Visible = col.Visible; - break; - } + column.Visible = col.Visible; + column.Width = col.Width; } } + // 重置可见缓存 + RebuildTableColumnFromCache(); + _resetColumns = true; _invoke = true; StateHasChanged(); @@ -1823,14 +1855,15 @@ private async Task OnContextMenu(MouseEventArgs e, TItem item) /// Gets or sets Resize Column Callback ///
[Parameter] - public Func? OnResizeColumnAsync { get; set; } + public Func? OnResizeColumnAsync { get; set; } /// /// 获得/设置 自动调整列宽回调方法 /// Gets or sets Auto Fit Column Width Callback + /// /// [Parameter] - public Func>? OnAutoFitColumnWidthCallback { get; set; } + public Func? OnAutoFitColumnWidthCallback { get; set; } /// /// 获得/设置 列宽自适应时是否包含表头 默认 true @@ -1861,7 +1894,7 @@ public async Task DragColumnCallback(int originIndex, int currentIndex) if (_columnVisibleItems.Count > originIndex) { var firstColumn = _columnVisibleItems[originIndex]; - if (firstColumn != null && _columnVisibleItems.Count > currentIndex) + if (_columnVisibleItems.Count > currentIndex) { var targetColumn = _columnVisibleItems[currentIndex]; _columnVisibleItems.Remove(firstColumn); @@ -1892,36 +1925,63 @@ public async Task DragColumnCallback(int originIndex, int currentIndex) /// Resize Column Method called by JavaScript /// [JSInvokable] - public async Task ResizeColumnCallback(string name, JsonElement state) + public async Task ResizeColumnCallback(string name, TableColumnClientStatus columnState) { - // 调整列宽时返回所有列状态,更新缓存数据中列宽度与可见性 - var columnState = state.Parse(); - if (columnState == null) + UpdateTableColumnState(columnState); + + // 触发回调 + if (OnResizeColumnAsync != null) { - return; + await OnResizeColumnAsync(name, columnState); + } + } + + /// + /// 列宽自适应回调方法 由 JavaScript 脚本调用 + /// Auto Fit Column Width Callback called by JavaScript + /// + [JSInvokable] + public async Task AutoFitColumnWidthCallback(string fieldName, TableColumnClientStatus columnState) + { + UpdateTableColumnState(columnState); + + if (OnAutoFitColumnWidthCallback != null) + { + await OnAutoFitColumnWidthCallback(fieldName, columnState); } + } - if (!string.IsNullOrEmpty(ClientTableName)) + private void UpdateTableColumnState(TableColumnClientStatus columnState) + { + // 更新缓存数据中列宽度 + foreach (var item in _tableColumnStateCache.Columns) { - // 更新缓存数据中列宽度 - foreach (var item in _tableColumnStateCache.Columns) + var colState = columnState.Columns.Find(i => i.Name == item.Name); + if (colState != null) { - var colState = columnState.Columns.Find(i => i.Name == item.Name); - if (colState != null) - { - item.Width = colState.Width; - } + item.Width = colState.Width; } - _tableColumnStateCache.TableWidth = columnState.TableWidth; } + _tableColumnStateCache.TableWidth = columnState.TableWidth; + } - // 触发回调 - if (OnResizeColumnAsync != null) + private void UpdateTableWidth() + { + if (_tableColumnStateCache.TableWidth > 0) { - var column = columnState.Columns.Find(i => i.Name == name); - if (column != null) + if (IsMultipleSelect) + { + _tableColumnStateCache.TableWidth += MultiColumnWidth; + } + + if (ShowLineNo) + { + _tableColumnStateCache.TableWidth += LineNoColumnWidth; + } + + if (ShowDetails()) { - await OnResizeColumnAsync(name, column.Width); + _tableColumnStateCache.TableWidth += DetailColumnWidth; } } } diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.js b/src/BootstrapBlazor/Components/Table/Table.razor.js index 25b6094d984..7d86c46490d 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.js +++ b/src/BootstrapBlazor/Components/Table/Table.razor.js @@ -643,17 +643,16 @@ const autoFitColumnWidth = async (table, col) => { span.style.removeProperty('width'); } - table.style.removeProperty('width'); const tableWidth = getTableWidth(table); - if (tableWidth) { - table.style.setProperty('width', `${tableWidth}px`); - } + table.style.setProperty('width', `${tableWidth}px`); }); resetColumnWidthTips(table, col); + const state = getColumnStateObject(table); saveColumnStateToLocalstorage(table, state); - await table.invoke.invokeMethodAsync(table.options.resizeColumnCallback, field, state) + + await table.invoke.invokeMethodAsync(table.options.autoFitColumnWidthCallback, field, state); } } @@ -670,7 +669,7 @@ const calcCellWidth = cell => { document.body.appendChild(div); const cellStyle = getComputedStyle(cell); - return getWidth(div) + parseFloat(cellStyle.getPropertyValue('padding-left')) + parseFloat(cellStyle.getPropertyValue('padding-right')) + parseFloat(cellStyle.getPropertyValue('border-left-width')) + parseFloat(cellStyle.getPropertyValue('border-right-width')) + 1; + return getWidth(div) + parseFloat(cellStyle.getPropertyValue('padding-left')) + parseFloat(cellStyle.getPropertyValue('padding-right')) + parseFloat(cellStyle.getPropertyValue('border-left-width')) + parseFloat(cellStyle.getPropertyValue('border-right-width')) + 1 | 0; } const closeAllTips = (columns, self) => { @@ -857,11 +856,12 @@ export function getColumnStates(tableName) { const columnWidthState = getColumnWidthState(tableName); if (columnWidthState) { + removeColumnVisibleState(tableName); + const columnVisibleStates = getColumnVisibleState(tableName); if (columnVisibleStates) { - //removeColumnVisibleState(tableName); + removeColumnWidthState(tableName); - //removeColumnWidthState(tableName); for (const item of columnWidthState.cols) { const { name } = item; const column = columnVisibleStates.find(i => i.name === name); @@ -879,7 +879,7 @@ export function getColumnStates(tableName) { } const getColumnStateFromLocalstorage = tableName => { - const columnStateKey = `bb-table-column-${tableName}`; + const columnStateKey = `bb-table-${tableName}`; return getLocalStorageValue(columnStateKey); } @@ -919,7 +919,7 @@ const getLocalStorageValue = key => { const saveColumnStateToLocalstorage = (table, state) => { const { options: { tableName } } = table; if (tableName) { - const columnStateKey = `bb-table-column-${tableName}`; + const columnStateKey = `bb-table-${tableName}`; const columnState = state ?? getColumnStateObject(table); localStorage.setItem(columnStateKey, JSON.stringify(columnState)); } @@ -958,13 +958,13 @@ const getTableWidth = table => { const colgroup = [...table.children].find(i => i.nodeName === 'COLGROUP'); for (const col of colgroup.children) { const width = parseInt(col.style.width); - if (isNaN(width) === false) { - tableWidth += width; - } - else { + if (isNaN(width)) { tableWidth = null; break; } + else { + tableWidth += width; + } } return (tableWidth ?? getWidth(table)) | 0; } diff --git a/src/BootstrapBlazor/Components/Table/TableColumnLocalstorageStatus.cs b/src/BootstrapBlazor/Components/Table/TableColumnClientStatus.cs similarity index 55% rename from src/BootstrapBlazor/Components/Table/TableColumnLocalstorageStatus.cs rename to src/BootstrapBlazor/Components/Table/TableColumnClientStatus.cs index fa37373e59d..a8099be4cc0 100644 --- a/src/BootstrapBlazor/Components/Table/TableColumnLocalstorageStatus.cs +++ b/src/BootstrapBlazor/Components/Table/TableColumnClientStatus.cs @@ -7,11 +7,23 @@ namespace BootstrapBlazor.Components; -class TableColumnLocalstorageStatus +/// +/// 表格列状态类 +/// Table Column Status Class +/// +public class TableColumnClientStatus { + /// + /// 列状态集合 + /// Column State Collection + /// [JsonPropertyName("cols")] public List Columns { get; set; } = []; + /// + /// 表格宽度 + /// Table Width + /// [JsonPropertyName("table")] public int TableWidth { get; set; } } diff --git a/src/BootstrapBlazor/Extensions/JsonElementExtesions.cs b/src/BootstrapBlazor/Extensions/JsonElementExtesions.cs deleted file mode 100644 index 72d65971c0c..00000000000 --- a/src/BootstrapBlazor/Extensions/JsonElementExtesions.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using System.Text.Json; - -namespace BootstrapBlazor.Components; - -static class JsonElementExtensions -{ - extension(JsonElement element) - { - public T? Parse(JsonSerializerDefaults options = JsonSerializerDefaults.Web) - { - try - { - return element.Deserialize(new JsonSerializerOptions(options)); - } - catch - { - return default; - } - } - } -} - diff --git a/test/UnitTest/Components/TableBoolFilterTest.cs b/test/UnitTest/Components/TableBoolFilterTest.cs index 3c8f02a74ca..ceec65c16ae 100644 --- a/test/UnitTest/Components/TableBoolFilterTest.cs +++ b/test/UnitTest/Components/TableBoolFilterTest.cs @@ -77,7 +77,7 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } class MockColumn : TableColumn diff --git a/test/UnitTest/Components/TableColumnFilterTest.cs b/test/UnitTest/Components/TableColumnFilterTest.cs index ea384a513d7..7c872a2033c 100644 --- a/test/UnitTest/Components/TableColumnFilterTest.cs +++ b/test/UnitTest/Components/TableColumnFilterTest.cs @@ -232,7 +232,7 @@ private class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } private class MockColumn : TableColumn diff --git a/test/UnitTest/Components/TableDateTimeFilterTest.cs b/test/UnitTest/Components/TableDateTimeFilterTest.cs index 502c9dbe7aa..c4849ffe043 100644 --- a/test/UnitTest/Components/TableDateTimeFilterTest.cs +++ b/test/UnitTest/Components/TableDateTimeFilterTest.cs @@ -85,7 +85,7 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } class MockColumn : TableColumn diff --git a/test/UnitTest/Components/TableEnumFilterTest.cs b/test/UnitTest/Components/TableEnumFilterTest.cs index 548008829b4..eaa08967d34 100644 --- a/test/UnitTest/Components/TableEnumFilterTest.cs +++ b/test/UnitTest/Components/TableEnumFilterTest.cs @@ -98,7 +98,7 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } class MockColumn : TableColumn diff --git a/test/UnitTest/Components/TableLookupFilterTest.cs b/test/UnitTest/Components/TableLookupFilterTest.cs index b290edfe69b..2a1b2d864ea 100644 --- a/test/UnitTest/Components/TableLookupFilterTest.cs +++ b/test/UnitTest/Components/TableLookupFilterTest.cs @@ -118,7 +118,7 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } class MockColumn : TableColumn diff --git a/test/UnitTest/Components/TableMultiFilterTest.cs b/test/UnitTest/Components/TableMultiFilterTest.cs index a79b5069147..baa5cc781ba 100644 --- a/test/UnitTest/Components/TableMultiFilterTest.cs +++ b/test/UnitTest/Components/TableMultiFilterTest.cs @@ -198,6 +198,6 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } } diff --git a/test/UnitTest/Components/TableMultiSelectFilterTest.cs b/test/UnitTest/Components/TableMultiSelectFilterTest.cs index cbd9697a541..c1faf44e412 100644 --- a/test/UnitTest/Components/TableMultiSelectFilterTest.cs +++ b/test/UnitTest/Components/TableMultiSelectFilterTest.cs @@ -93,7 +93,7 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } class MockColumn : TableColumn diff --git a/test/UnitTest/Components/TableNotSupportFilterTest.cs b/test/UnitTest/Components/TableNotSupportFilterTest.cs index 7001e5676e2..d1127fdfed6 100644 --- a/test/UnitTest/Components/TableNotSupportFilterTest.cs +++ b/test/UnitTest/Components/TableNotSupportFilterTest.cs @@ -34,7 +34,7 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } class MockColumn : TableColumn> diff --git a/test/UnitTest/Components/TableNumberFilterTest.cs b/test/UnitTest/Components/TableNumberFilterTest.cs index 3e9301507a6..206bb4c5ae7 100644 --- a/test/UnitTest/Components/TableNumberFilterTest.cs +++ b/test/UnitTest/Components/TableNumberFilterTest.cs @@ -106,7 +106,7 @@ class MockTable : ITable public List Columns => []; - public IEnumerable GetVisibleColumns() => Columns; + public List GetVisibleColumns() => Columns; } class MockColumn : TableColumn diff --git a/test/UnitTest/Components/TableTest.cs b/test/UnitTest/Components/TableTest.cs index e25a595a07c..927f16f5b52 100644 --- a/test/UnitTest/Components/TableTest.cs +++ b/test/UnitTest/Components/TableTest.cs @@ -272,8 +272,8 @@ public void ResetVisibleColumns_Ok() { table.ResetVisibleColumns( [ - new(nameof(Foo.Name), true) { DisplayName = "Name-Display" }, - new(nameof(Foo.Address), false), + new TableColumnState() { Name = nameof(Foo.Name), Visible = true, DisplayName = "Name-Display" }, + new TableColumnState() { Name = nameof(Foo.Address), Visible = false } ]); } return Task.CompletedTask; @@ -897,12 +897,12 @@ public void ResetFilter_Null() public async Task ShowColumnList_Ok() { // 设置客户端存储 - Context.JSInterop.Setup>("reloadColumnList", "test").SetResult( - [ - null, - new("Name", false), - new("Address", true) - ]); + var state = new TableColumnClientStatus(); + state.TableWidth = 500; + state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Name), Visible = false, DisplayName = "Name-Display" }); + state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Address), Visible = true, Width = 120, DisplayName = "Address-Display" }); + + Context.JSInterop.Setup("getColumnStates", "test").SetResult(state); var show = false; var localizer = Context.Services.GetRequiredService>(); var cut = Context.Render(pb => @@ -945,6 +945,7 @@ public async Task ShowColumnList_Ok() var item = cut.FindComponents>()[0]; await cut.InvokeAsync(item.Instance.OnToggleClick); Assert.True(show); + cut.Contains(""); await cut.InvokeAsync(item.Instance.OnToggleClick); Assert.False(show); @@ -955,6 +956,27 @@ public async Task ShowColumnList_Ok() pb.Add(a => a.IsPopoverToolbarDropdownButton, true); }); table.Contains("dropdown-menu-popover"); + + state.Columns[0].Width = 100; + await cut.InvokeAsync(item.Instance.OnToggleClick); + Assert.True(show); + + cut.Contains("style=\"width: 220px;\""); + + table.Render(pb => + { + pb.Add(a => a.IsMultipleSelect, true); + pb.Add(a => a.ShowLineNo, true); + pb.Add(a => a.IsDetails, true); + pb.Add(a => a.DetailRowTemplate, foo => builder => builder.AddContent(0, "test_DetailRowTemplate")); + }); + await cut.InvokeAsync(item.Instance.OnToggleClick); + Assert.False(show); + cut.Contains("style=\"width: 240px;\""); + + await cut.InvokeAsync(item.Instance.OnToggleClick); + Assert.True(show); + cut.Contains("style=\"width: 340px;\""); } [Fact] @@ -1775,27 +1797,27 @@ public void ColumnFixed_Ok(bool showExtendButton, bool isFixedHeader) builder.AddAttribute(3, "Width", 100); builder.CloseComponent(); - builder.OpenComponent>(10); - builder.AddAttribute(11, "Field", foo.Address); - builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); + builder.OpenComponent>(10); + builder.AddAttribute(11, "Field", foo.Complete); + builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(Foo.Complete), typeof(bool))); builder.CloseComponent(); builder.OpenComponent>(10); builder.AddAttribute(11, "Field", foo.Address); - builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); - builder.AddAttribute(13, nameof(TableColumn.Fixed), true); + builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(foo.Address), typeof(string))); + builder.AddAttribute(13, nameof(TableColumn<,>.Fixed), true); builder.CloseComponent(); - builder.OpenComponent>(10); - builder.AddAttribute(11, "Field", foo.Address); - builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); - builder.AddAttribute(13, nameof(TableColumn.Fixed), true); + builder.OpenComponent>(10); + builder.AddAttribute(11, "Field", foo.Education); + builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(foo.Education), typeof(EnumEducation?))); + builder.AddAttribute(13, nameof(TableColumn<,>.Fixed), true); builder.AddAttribute(3, "Width", 100); builder.CloseComponent(); - builder.OpenComponent>(10); - builder.AddAttribute(11, "Field", foo.Address); - builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); + builder.OpenComponent>>(10); + builder.AddAttribute(11, "Field", foo.Hobby); + builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(foo.Hobby), typeof(IEnumerable))); builder.AddAttribute(13, nameof(TableColumn.Fixed), true); builder.CloseComponent(); }); @@ -1804,35 +1826,102 @@ public void ColumnFixed_Ok(bool showExtendButton, bool isFixedHeader) cut.Contains("left: 0px;"); cut.Contains("left: 200px;"); - cut.Contains("left: 500px;"); if (showExtendButton) { if (isFixedHeader) { - cut.Contains("right: 238px;"); + cut.Contains("right: 438px;"); + cut.Contains("right: 338px;"); cut.Contains("right: 138px;"); cut.Contains("right: 8px;"); } else { - cut.Contains("right: 230px;"); + cut.Contains("right: 430px;"); + cut.Contains("right: 330px;"); cut.Contains("right: 130px;"); cut.Contains("right: 0px;"); } } if (!showExtendButton) { - cut.Contains("right: 100px;"); + cut.Contains("right: 300px;"); + cut.Contains("right: 200px;"); cut.Contains("right: 0px;"); if (isFixedHeader) { - cut.Contains("right: 108px;"); + cut.Contains("right: 308px;"); + cut.Contains("right: 208px;"); cut.Contains("right: 8px;"); } } } + [Fact] + public void ColumnFixed_TailColumn_Ok() + { + var localizer = Context.Services.GetRequiredService>(); + var cut = Context.Render(pb => + { + pb.AddChildContent>(pb => + { + pb.Add(a => a.RenderMode, TableRenderMode.Table); + pb.Add(a => a.Items, Foo.GenerateFoo(localizer, 2)); + pb.Add(a => a.TableColumns, foo => builder => + { + builder.OpenComponent>(0); + builder.AddAttribute(1, "Field", foo.Name); + builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(Foo.Name), typeof(string))); + builder.AddAttribute(3, nameof(TableColumn<,>.Fixed), true); + builder.AddAttribute(4, nameof(TableColumn<,>.Width), 100); + builder.CloseComponent(); + + builder.OpenComponent>(5); + builder.AddAttribute(6, "Field", foo.Count); + builder.AddAttribute(7, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(Foo.Count), typeof(int))); + builder.AddAttribute(8, nameof(TableColumn<,>.Fixed), true); + builder.AddAttribute(9, nameof(TableColumn<,>.Width), 100); + builder.CloseComponent(); + + builder.OpenComponent>(10); + builder.AddAttribute(11, "Field", foo.Address); + builder.AddAttribute(12, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(Foo.Address), typeof(string))); + builder.AddAttribute(13, nameof(TableColumn<,>.Width), 100); + builder.CloseComponent(); + + builder.OpenComponent>(14); + builder.AddAttribute(15, "Field", foo.DateTime); + builder.AddAttribute(16, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(Foo.DateTime), typeof(DateTime?))); + builder.AddAttribute(17, nameof(TableColumn<,>.Fixed), true); + builder.AddAttribute(18, nameof(TableColumn<,>.Width), 100); + builder.CloseComponent(); + + builder.OpenComponent>(19); + builder.AddAttribute(20, "Field", foo.Education); + builder.AddAttribute(21, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(Foo.Education), typeof(EnumEducation?))); + builder.AddAttribute(22, nameof(TableColumn<,>.Fixed), true); + builder.AddAttribute(23, nameof(TableColumn<,>.Width), 100); + builder.CloseComponent(); + + builder.OpenComponent>(24); + builder.AddAttribute(25, "Field", foo.Complete); + builder.AddAttribute(26, "FieldExpression", Utility.GenerateValueExpression(foo, nameof(Foo.Complete), typeof(bool))); + builder.AddAttribute(27, nameof(TableColumn<,>.Fixed), true); + builder.AddAttribute(28, nameof(TableColumn<,>.Width), 100); + builder.CloseComponent(); + }); + }); + }); + + cut.Contains("style=\"left: 0px;\""); + cut.Contains("style=\"left: 100px;\""); + cut.Contains("style=\"right: 200px;\""); + cut.Contains("style=\"right: 100px;\""); + cut.Contains("style=\"right: 0px;\""); + cut.DoesNotContain("style=\"left: 300px;\""); + } + [Fact] public void ScrollWidth_Ok() { @@ -6107,167 +6196,6 @@ public async Task ToggleLoading_Ok() await cut.InvokeAsync(() => table.Instance.QueryAsync()); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void ReloadColumnWidth_Ok(bool fixedHeader) - { - Context.JSInterop.Setup("reloadColumnWidth", "test_client_name").SetResult(""" - { - "cols": [ - { "name": "Name", "width": 20 }, - { "name": "Address", "width": 80 } - ], - "table": 100 - } - """); - var localizer = Context.Services.GetRequiredService>(); - var items = Foo.GenerateFoo(localizer, 2); - var cut = Context.Render(pb => - { - pb.AddChildContent>(pb => - { - pb.Add(a => a.IsFixedHeader, fixedHeader); - pb.Add(a => a.RenderMode, TableRenderMode.Table); - pb.Add(a => a.ClientTableName, "test_client_name"); - pb.Add(a => a.AllowResizing, true); - pb.Add(a => a.Items, items); - pb.Add(a => a.TableColumns, foo => builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Name"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string))); - builder.CloseComponent(); - - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Address"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); - builder.CloseComponent(); - }); - }); - }); - var table = cut.FindComponent>(); - Assert.Contains("style=\"width: 100px;\"", table.Markup); - } - - [Fact] - public void ReloadColumnWidth_TableWidth_Invalid() - { - Context.JSInterop.Setup("reloadColumnWidth", "test_client_name").SetResult(""" - { - "cols": [ - { "name": "Name", "width": 20 }, - { "name": "Address", "width": 80 } - ], - "table": 123.12 - } - """); - var localizer = Context.Services.GetRequiredService>(); - var items = Foo.GenerateFoo(localizer, 2); - var cut = Context.Render(pb => - { - pb.AddChildContent>(pb => - { - pb.Add(a => a.RenderMode, TableRenderMode.Table); - pb.Add(a => a.ClientTableName, "test_client_name"); - pb.Add(a => a.AllowResizing, true); - pb.Add(a => a.Items, items); - pb.Add(a => a.TableColumns, foo => builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Name"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string))); - builder.CloseComponent(); - - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Address"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); - builder.CloseComponent(); - }); - }); - }); - var table = cut.FindComponent>(); - Assert.Contains("", table.Markup); - } - - [Fact] - public void ReloadColumnWidth_NoTableElement() - { - Context.JSInterop.Setup("reloadColumnWidth", "test_client_name").SetResult(""" - { - "cols": [ - { "name": "Name", "width": 20 }, - { "name": "Address", "width": 80 } - ] - } - """); - var localizer = Context.Services.GetRequiredService>(); - var items = Foo.GenerateFoo(localizer, 2); - var cut = Context.Render(pb => - { - pb.AddChildContent>(pb => - { - pb.Add(a => a.RenderMode, TableRenderMode.Table); - pb.Add(a => a.ClientTableName, "test_client_name"); - pb.Add(a => a.AllowResizing, true); - pb.Add(a => a.Items, items); - pb.Add(a => a.TableColumns, foo => builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Name"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string))); - builder.CloseComponent(); - - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Address"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); - builder.CloseComponent(); - }); - }); - }); - var table = cut.FindComponent>(); - Assert.Contains("", table.Markup); - } - - [Fact] - public void ReloadColumnWidth_Columns_Invalid() - { - Context.JSInterop.Setup("reloadColumnWidth", "test_client_name").SetResult(""" - { - "cols": { - "name": "Name", - "name": "Address" - } - } - """); - var localizer = Context.Services.GetRequiredService>(); - var items = Foo.GenerateFoo(localizer, 2); - var cut = Context.Render(pb => - { - pb.AddChildContent>(pb => - { - pb.Add(a => a.RenderMode, TableRenderMode.Table); - pb.Add(a => a.ClientTableName, "test_client_name"); - pb.Add(a => a.AllowResizing, true); - pb.Add(a => a.Items, items); - pb.Add(a => a.TableColumns, foo => builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Name"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string))); - builder.CloseComponent(); - - builder.OpenComponent>(0); - builder.AddAttribute(1, "Field", "Address"); - builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); - builder.CloseComponent(); - }); - }); - }); - var table = cut.FindComponent>(); - Assert.DoesNotContain("", table.Markup); - } - [Fact] public async Task FitAllColumnWidth_Ok() { @@ -6372,7 +6300,7 @@ public async Task OnBreakPointChanged_Ok() Assert.Equal(2, cols.Count); var resp = cut.FindComponent().Instance; - await resp.OnResize(BreakPoint.Small); + await cut.InvokeAsync(() => resp.OnResize(BreakPoint.Small)); var row = table.Find("tbody > tr"); Assert.Equal(1, row.ChildElementCount); @@ -8739,6 +8667,7 @@ public void ShowRowCheckboxCallback_Ok() public async Task OnAutoFitColumnWidthCallback_Ok() { var name = ""; + TableColumnClientStatus? clientState = null; var localizer = Context.Services.GetRequiredService>(); var cut = Context.Render(pb => { @@ -8749,11 +8678,11 @@ public async Task OnAutoFitColumnWidthCallback_Ok() pb.Add(a => a.ClientTableName, "table-unit-test"); pb.Add(a => a.OnQueryAsync, OnQueryAsync(localizer)); pb.Add(a => a.FitColumnWidthIncludeHeader, true); - pb.Add(a => a.OnAutoFitColumnWidthCallback, (fieldName, calcWidth) => + pb.Add(a => a.OnAutoFitColumnWidthCallback, (fieldName, state) => { name = fieldName; - var resWidth = Math.Max(100.65f, calcWidth); - return Task.FromResult(resWidth); + clientState = state; + return Task.CompletedTask; }); pb.Add(a => a.TableColumns, foo => builder => { @@ -8771,17 +8700,14 @@ public async Task OnAutoFitColumnWidthCallback_Ok() }); var table = cut.FindComponent>(); - float v = 0f; - await cut.InvokeAsync(async () => v = await table.Instance.AutoFitColumnWidthCallback("DateTime", 90)); - Assert.Equal(100.65f, v); + var state = new TableColumnClientStatus() { Columns = [] }; + await cut.InvokeAsync(() => table.Instance.AutoFitColumnWidthCallback(nameof(Foo.DateTime), state)); + Assert.NotNull(clientState); } [Fact] public async Task AllowDragColumn_Ok() { - Context.JSInterop.Setup>("reloadColumnOrder", "table-unit-test").SetResult(["Name", "Address"]); - Context.JSInterop.SetupVoid("saveColumnOrder").SetVoidResult(); - var name = ""; var localizer = Context.Services.GetRequiredService>(); var cut = Context.Render(pb => @@ -8820,10 +8746,7 @@ public async Task AllowDragColumn_Ok() }); var table = cut.FindComponent>(); - await cut.InvokeAsync(async () => - { - await table.Instance.DragColumnCallback(1, 0); - }); + await cut.InvokeAsync(() => table.Instance.DragColumnCallback(1, 0)); Assert.Equal("Address", name); var columns = cut.FindAll("th"); @@ -8850,19 +8773,27 @@ await cut.InvokeAsync(async () => [Fact] public async Task OnResizeColumnCallback_Ok() { + var state = new TableColumnClientStatus(); + state.TableWidth = 500; + state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Name), Visible = false, DisplayName = "Name-Display" }); + state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Address), Visible = true, Width = 120, DisplayName = "Address-Display" }); + + Context.JSInterop.Setup("getColumnStates", "test").SetResult(state); + var name = ""; - var width = 0f; + TableColumnClientStatus? clientState = null; var localizer = Context.Services.GetRequiredService>(); var cut = Context.Render(pb => { pb.AddChildContent>(pb => { + pb.Add(a => a.ClientTableName, "test"); pb.Add(a => a.RenderMode, TableRenderMode.Table); pb.Add(a => a.AllowResizing, true); - pb.Add(a => a.OnResizeColumnAsync, (field, colWidth) => + pb.Add(a => a.OnResizeColumnAsync, (field, state) => { name = field; - width = colWidth; + clientState = state; return Task.CompletedTask; }); pb.Add(a => a.OnQueryAsync, OnQueryAsync(localizer)); @@ -8882,11 +8813,59 @@ public async Task OnResizeColumnCallback_Ok() }); var table = cut.FindComponent>(); - await cut.InvokeAsync(() => table.Instance.ResizeColumnCallback(1, 100)); + var newState = new TableColumnClientStatus(); + newState.TableWidth = 100; + newState.Columns.Add(new TableColumnState() { Name = "Name", Width = 50 }); + newState.Columns.Add(new TableColumnState() { Name = "Address", Width = 50 }); + await cut.InvokeAsync(() => table.Instance.ResizeColumnCallback(nameof(Foo.Address), newState)); Assert.Equal("Address", name); - Assert.Equal(100, width); + Assert.NotNull(clientState); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ReloadColumnWidth_Ok(bool fixedHeader) + { + var state = new TableColumnClientStatus(); + state.TableWidth = 220; + state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Name), Visible = true, Width = 100, DisplayName = "Name-Display" }); + state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Address), Visible = true, Width = 120, DisplayName = "Address-Display" }); + + Context.JSInterop.Setup("getColumnStates", "test_client_name").SetResult(state); + + var localizer = Context.Services.GetRequiredService>(); + var items = Foo.GenerateFoo(localizer, 2); + var cut = Context.Render(pb => + { + pb.AddChildContent>(pb => + { + pb.Add(a => a.IsFixedHeader, fixedHeader); + pb.Add(a => a.RenderMode, TableRenderMode.Table); + pb.Add(a => a.ClientTableName, "test_client_name"); + pb.Add(a => a.AllowResizing, true); + pb.Add(a => a.Items, items); + pb.Add(a => a.TableColumns, foo => builder => + { + builder.OpenComponent>(0); + builder.AddAttribute(1, "Field", "Name"); + builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string))); + builder.CloseComponent(); - await cut.InvokeAsync(() => table.Instance.ResizeColumnCallback(20, 100)); + builder.OpenComponent>(0); + builder.AddAttribute(1, "Field", "Address"); + builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); + builder.CloseComponent(); + }); + }); + }); + var table = cut.FindComponent>(); + + Assert.Contains("style=\"width: 220px;\"", table.Markup); + if (fixedHeader) + { + Assert.Contains("style=\"width: 215px;\"", table.Markup); + } } [Theory] @@ -9230,6 +9209,48 @@ public async Task ShowColumnListControls_Ok() await cut.InvokeAsync(() => buttons[0].Click()); } + [Fact] + private async Task UpdateTableState_Ok() + { + var argumentsCount = 0; + object? obj = null; + Context.JSInterop.SetupVoid("updateTableState", invocationMatcher => + { + argumentsCount = invocationMatcher.Arguments.Count; + obj = invocationMatcher.Arguments[1]; + return true; + }); + + var localizer = Context.Services.GetRequiredService>(); + var cut = Context.Render>(pb => + { + pb.Add(a => a.ScrollIntoViewBehavior, ScrollIntoViewBehavior.Auto); + pb.Add(a => a.TableColumns, foo => builder => + { + builder.OpenComponent>(0); + builder.AddAttribute(1, "Field", "Name"); + builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string))); + builder.CloseComponent(); + + builder.OpenComponent>(0); + builder.AddAttribute(1, "Field", "Address"); + builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string))); + builder.CloseComponent(); + }); + pb.Add(a => a.RenderMode, TableRenderMode.Table); + pb.Add(a => a.Items, Foo.GenerateFoo(localizer)); + }); + + // 更新客户端持久化键值 + cut.Render(pb => + { + pb.Add(a => a.ClientTableName, "table-unit-test"); + }); + + Assert.Equal(2, argumentsCount); + Assert.NotNull(obj); + } + class SortableList : ISortableList { } static bool ProhibitEdit(Table @this) @@ -9527,7 +9548,7 @@ private class MockTable : Table { public TableRenderMode ShouldBeTable() { - ScreenSize = BreakPoint.Large; + InvokeScreen(BreakPoint.Large); RenderModeResponsiveWidth = BreakPoint.Medium; RenderMode = TableRenderMode.Auto; return base.ActiveRenderMode; @@ -9535,7 +9556,7 @@ public TableRenderMode ShouldBeTable() public TableRenderMode ShouldBeCardView() { - ScreenSize = BreakPoint.ExtraSmall; + InvokeScreen(BreakPoint.ExtraSmall); RenderModeResponsiveWidth = BreakPoint.Medium; RenderMode = TableRenderMode.Auto; return base.ActiveRenderMode; @@ -9575,6 +9596,14 @@ public async Task TestDeleteAsync() public string? TestGetCellClassString(ITableColumn col) => base.GetCellClassString(col, false, false); public string? TestGetHeaderWrapperClassString(ITableColumn col) => base.GetHeaderWrapperClassString(col); + + private void InvokeScreen(object val) + { + var fieldInfo = GetType().BaseType!.GetField("_screenSize", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(fieldInfo); + + fieldInfo.SetValue(this, val); + } } private class MockRenderCellTable : Table diff --git a/test/UnitTest/Converters/ColumnVisibleItemConverterTest.cs b/test/UnitTest/Converters/ColumnVisibleItemConverterTest.cs deleted file mode 100644 index a008df3d416..00000000000 --- a/test/UnitTest/Converters/ColumnVisibleItemConverterTest.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using System.Text.Json; - -namespace UnitTest.Converters; - -public class ColumnVisibleItemConverterTest -{ - [Fact] - public void ColumnVisibleItemConverter_Ok() - { - var item = new ColumnVisibleItem("name", true) { DisplayName = "display" }; - var json = JsonSerializer.Serialize(item); - Assert.Equal("{\"name\":\"name\",\"visible\":true}", json); - - var item2 = JsonSerializer.Deserialize>("[{\"test\":\"test\"}]"); - } -} diff --git a/test/UnitTest/Converters/JsonDescriptionEnumConverterTest.cs b/test/UnitTest/Converters/JsonDescriptionEnumConverterTest.cs index 4e02dc73c57..8e0a87dac86 100644 --- a/test/UnitTest/Converters/JsonDescriptionEnumConverterTest.cs +++ b/test/UnitTest/Converters/JsonDescriptionEnumConverterTest.cs @@ -52,20 +52,6 @@ public void JsonEnumConverter_Ok() Assert.Equal("\"\"", json); } - [Fact] - public void ColumnVisibleItemConverter_Ok() - { - var item = new ColumnVisibleItem("name", true) { DisplayName = "display" }; - var json = JsonSerializer.Serialize(item); - - Assert.Equal("{\"name\":\"name\",\"visible\":true}", json); - - var item1 = JsonSerializer.Deserialize(json); - Assert.NotNull(item1); - Assert.Equal("name", item1.Name); - Assert.True(item1.Visible); - } - [JsonConverter(typeof(JsonDescriptionEnumConverter))] public enum TestEnum { diff --git a/test/UnitTest/Dynamic/ChangeDetectionCleanTaskTest.cs b/test/UnitTest/Dynamic/ChangeDetectionCleanTaskTest.cs index 41a8db9be5f..fce7fc4847a 100644 --- a/test/UnitTest/Dynamic/ChangeDetectionCleanTaskTest.cs +++ b/test/UnitTest/Dynamic/ChangeDetectionCleanTaskTest.cs @@ -92,6 +92,6 @@ class MockTable : ITable public List Columns { get; } = []; - public IEnumerable GetVisibleColumns() => []; + public List GetVisibleColumns() => []; } }