diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/Tables.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/Tables.razor.cs index 046df990108..90b5dc9f933 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/Tables.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/Tables.razor.cs @@ -646,6 +646,22 @@ private AttributeItem[] GetAttributes() => DefaultValue = "false" }, new() + { + Name = nameof(Table.IsKeepSelectedRows), + Description = Localizer["IsKeepSelectedRowsAttr"], + Type = "boolean", + ValueList = "true / false", + DefaultValue = "false" + }, + new() + { + Name = nameof(Table.IsKeepSelectedRowAfterAdd), + Description = Localizer["IsKeepSelectedRowAfterAddAttr"], + Type = "boolean", + ValueList = "true / false", + DefaultValue = "false" + }, + new() { Name = "ClickToSelect", Description = Localizer["ClickToSelectAttr"], diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 5efed3fc73a..118f16ed38e 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -4894,6 +4894,8 @@ "IsTreeAttr": "Is it tree data", "IsDetailsAttr": "Whether it is a detail row table, use DetailRowTemplate for logical judgment when not set", "IsHideFooterWhenNoDataAttr": "Whether to show Footer when no data is available", + "IsKeepSelectedRowsAttr": "Whether to keep the selected row after switch page index", + "IsKeepSelectedRowAfterAddAttr": "Whether to keep the selected row after call add method", "ClickToSelectAttr": "Click on the line to select the line", "ShowCheckboxTextAttr": "Selection column that displays text", "ShowFooterAttr": "Show feet", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index fa57839b0d5..af0183f5542 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -4894,6 +4894,8 @@ "IsTreeAttr": "是否为树形数据", "IsDetailsAttr": "是否为明细行表格,未设置时使用 DetailRowTemplate 进行逻辑判断", "IsHideFooterWhenNoDataAttr": "无数据时是否显示 Footer", + "IsKeepSelectedRowsAttr": "翻页后是否保持选中行数据", + "IsKeepSelectedRowAfterAddAttr": "新建数据后是否保持选中行", "ClickToSelectAttr": "点击行即选中本行", "ShowCheckboxTextAttr": "显示文字的选择列", "ShowFooterAttr": "是否显示表脚", diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 915c153e1de..30a2b24ecd5 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@ - 8.10.2-beta03 + 8.10.2-beta04 diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs index 1d544ef1bf3..446088d053b 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Checkbox.cs @@ -24,6 +24,12 @@ public partial class Table [Parameter] public bool IsKeepSelectedRows { get; set; } + /// + /// 获得/设置 新建数据是否保持原选择行,默认为 false 不保持 + /// + [Parameter] + public bool IsKeepSelectedRowAfterAdd { get; set; } + /// /// 获得 表头行是否选中状态 /// diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs index 0d3acf7326a..b59fef919e7 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs @@ -287,21 +287,18 @@ private async Task InternalOnAddAsync() [Parameter] public Func? CreateItemCallback { get; set; } - private TItem CreateTItem() + private TItem CreateTItem() => CreateItemCallback?.Invoke() ?? CreateInstance(); + + private TItem CreateInstance() { - var item = CreateItemCallback?.Invoke(); - if (item == null) + try { - try - { - item = Activator.CreateInstance(); - } - catch (Exception) - { - throw new InvalidOperationException($"{typeof(TItem)} missing new() method. Please provider {nameof(CreateItemCallback)} create the {typeof(TItem)} instance. {typeof(TItem)} 未提供无参构造函数 new() 请通过 {nameof(CreateItemCallback)} 回调方法创建实例"); - } + return Activator.CreateInstance(); + } + catch (Exception) + { + throw new InvalidOperationException($"{typeof(TItem)} missing new() method. Please provider {nameof(CreateItemCallback)} create the {typeof(TItem)} instance. {typeof(TItem)} 未提供无参构造函数 new() 请通过 {nameof(CreateItemCallback)} 回调方法创建实例"); } - return item; } /// diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs index 54ec93e9dda..efc1c7c7d7d 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs @@ -486,8 +486,12 @@ public async Task AddAsync() // 数据源为 DataTable 新建后重建行与列 await DynamicContext.AddAsync(SelectedRows.OfType()); ResetDynamicContext(); - SelectedRows.Clear(); - await OnSelectedRowsChanged(); + + if (!IsKeepSelectedRowAfterAdd) + { + SelectedRows.Clear(); + await OnSelectedRowsChanged(); + } } else if (IsExcel) { diff --git a/test/UnitTest/Components/TableTest.cs b/test/UnitTest/Components/TableTest.cs index d778ae52c08..682745b4e8a 100644 --- a/test/UnitTest/Components/TableTest.cs +++ b/test/UnitTest/Components/TableTest.cs @@ -185,7 +185,7 @@ await cut.InvokeAsync(() => [Theory] [InlineData(InsertRowMode.First)] [InlineData(InsertRowMode.Last)] - public void Items_EditForm_Add(InsertRowMode insertMode) + public async Task Items_EditForm_Add(InsertRowMode insertMode) { var updated = false; var localizer = Context.Services.GetRequiredService>(); @@ -206,7 +206,7 @@ public void Items_EditForm_Add(InsertRowMode insertMode) }); }); var table = cut.FindComponent>(); - _ = table.Instance.AddAsync(); + await cut.InvokeAsync(table.Instance.AddAsync); Assert.True(updated); Assert.Equal(2, table.Instance.Rows.Count); } @@ -6046,6 +6046,35 @@ public async Task DynamicContext_Add() await cut.InvokeAsync(() => delete.Instance.OnConfirm()); } + [Fact] + public async Task IsKeepSelectedRowAfterAdd_Ok() + { + var localizer = Context.Services.GetRequiredService>(); + var items = Foo.GenerateFoo(localizer, 2); + var cut = Context.RenderComponent(pb => + { + pb.AddChildContent>(pb => + { + pb.Add(a => a.RenderMode, TableRenderMode.Table); + pb.Add(a => a.IsMultipleSelect, true); + pb.Add(a => a.IsKeepSelectedRowAfterAdd, true); + pb.Add(a => a.DynamicContext, CreateDynamicContext(localizer)); + }); + }); + + var table = cut.FindComponent>(); + + // 选中第一行数据 + var input = cut.Find("tbody .form-check-input"); + await cut.InvokeAsync(() => input.Click()); + var selectedRow = table.Instance.SelectedRows.FirstOrDefault(); + Assert.NotNull(selectedRow); + + await cut.InvokeAsync(() => table.Instance.AddAsync()); + selectedRow = table.Instance.SelectedRows.FirstOrDefault(); + Assert.NotNull(selectedRow); + } + [Fact] public async Task DynamicContext_Edit() {