From 6be1e5d96d2aa22d5538f5122b4d6babb588e298 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 10 Jun 2026 16:02:56 +0800 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=B6=88=E9=99=A4=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Table/TablesDynamicObject.razor.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs index 315234a3452..1cc01088e61 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs @@ -66,7 +66,7 @@ private static IEnumerable GenerateDynamicColumn return ret; } - private readonly static Random random = new(); + private static readonly Random Random = new(); private Task> OnQueryAsync(QueryPageOptions options) { @@ -79,10 +79,9 @@ private Task> OnQueryAsync(QueryPageOptions options private Dictionary GenerateDynamicRowData(int index) { var ret = new Dictionary(); - for (int i = 0; i < _dynamicColumnList.Count; i++) + foreach (var columnName in _dynamicColumnList) { - var columnName = _dynamicColumnList[i]; - object? value = random.Next(1000, 9999); + object? value = Random.Next(1000, 9999); ret.Add(columnName, value); } return ret; From 118f632b1a2cb02b08e3ac9b99518f585417df76 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 10 Jun 2026 16:06:01 +0800 Subject: [PATCH 2/9] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Table/TablesDynamicObject.razor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs index 1cc01088e61..867216438d1 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamicObject.razor.cs @@ -76,12 +76,12 @@ private Task> OnQueryAsync(QueryPageOptions options return Task.FromResult(new QueryData() { Items = items, TotalCount = 10, IsSorted = true, IsFiltered = true }); } - private Dictionary GenerateDynamicRowData(int index) + private Dictionary GenerateDynamicRowData(int _) { var ret = new Dictionary(); foreach (var columnName in _dynamicColumnList) { - object? value = Random.Next(1000, 9999); + var value = Random.Next(1000, 9999); ret.Add(columnName, value); } return ret; From 76ad7eb7c58f600f5e667fbd5ec805443da1b1eb Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 10 Jun 2026 17:15:15 +0800 Subject: [PATCH 3/9] =?UTF-8?q?doc:=20=E9=87=8D=E6=9E=84=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Samples/Table/TablesDynamic.razor | 26 ++- .../Samples/Table/TablesDynamic.razor.cs | 201 ++++++++++-------- 2 files changed, 126 insertions(+), 101 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor index 2317f334116..1540e74161d 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor @@ -7,19 +7,25 @@

@Localizer["TablesDynamicDescription"]

+

注意事项:

+

DataTableDynamicContext 对象底层是通过 Emit 技术将 DataTable 行转成动态类型的,所以每创建一次 DataTableDynamicContext 底层就会创建一个动态程序集,所以实际项目中应该尽量避免重复创建动态程序集

+

可以通过设置 DataTableDynamicContext 属性 UseCache="false" 关闭内部的数据缓存,在自己的代码逻辑中更新 DataTableDynamicContextDataTable 属性,大大提高系统性能

+ +

+
 
-    
+    
@((MarkupString)Localizer["TablesDynamicEditDescription"].Value)
- + ShowToolbar="true" ShowExtendButtons="true">
@foreach (var item in SelectedItems) { @@ -31,12 +37,16 @@ - - - + + + +
@@ -44,6 +54,6 @@ - - +
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs index 53cb293a61b..689b49853df 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs @@ -12,10 +12,10 @@ namespace BootstrapBlazor.Server.Components.Samples.Table; /// public partial class TablesDynamic { - [NotNull] - private DataTableDynamicContext? DataTableDynamicContext { get; set; } - - private DataTable UserData { get; } = new DataTable(); + private DataTableDynamicContext? _dataTableDynamicContext1; + private DataTableDynamicContext? _dataTableDynamicContext2; + private DataTableDynamicContext? _dataTableDynamicContext3; + private DataTableDynamicContext? _dataTableDynamicContext4; private List SelectedItems { get; set; } = []; @@ -33,19 +33,47 @@ protected override void OnInitialized() ButtonAddColumnText ??= Localizer["TablesDynamicDynamicColButtonAddColumnText"]; ButtonRemoveColumnText ??= Localizer["TablesDynamicDynamicColButtonRemoveColumnText"]; - // 初始化 DataTable - InitDataTable(); - - // 初始化分页表格 - InitPageDataTable(); + InitDataTableContext(); } - private static bool ModelEqualityComparer(IDynamicObject x, IDynamicObject y) => x.GetValue("Id")?.ToString() == y.GetValue("Id")?.ToString(); + private DataTable CreateDataTable() + { + var dataTable = new DataTable(); + dataTable.Columns.Add(nameof(Foo.Id), typeof(int)); + dataTable.Columns.Add(nameof(Foo.DateTime), typeof(DateTime)); + dataTable.Columns.Add(nameof(Foo.Name), typeof(string)); + dataTable.Columns.Add(nameof(Foo.Count), typeof(int)); + dataTable.PrimaryKey = + [ + dataTable.Columns[0] + ]; + dataTable.Columns[0].AutoIncrement = true; + Foo.GenerateFoo(FooLocalizer, 10).ForEach(f => { dataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); }); + dataTable.AcceptChanges(); + + return dataTable; + } - private void CreateContext() + private void InitDataTableContext() { - // 初始化动态类型上下文实例 - DataTableDynamicContext = new DataTableDynamicContext(UserData, (context, col) => + var table = CreateDataTable(); + _dataTableDynamicContext1 = CreateContext(table); + + table = CreateDataTable(); + _dataTableDynamicContext2 = CreateContext(table); + + table = CreateDataTable(); + _dataTableDynamicContext3 = CreateContext(table); + + CreatePageDataTable(); + RebuildPaginationDataTable(); + } + + private static bool ModelEqualityComparer(IDynamicObject x, IDynamicObject y) => + x.GetValue("Id")?.ToString() == y.GetValue("Id")?.ToString(); + + private DataTableDynamicContext CreateContext(DataTable table) => new DataTableDynamicContext(table, + (context, col) => { var propertyName = col.GetFieldName(); // 使用 Text 设置显示名称示例 @@ -54,7 +82,10 @@ private void CreateContext() { context.AddRequiredAttribute(nameof(Foo.DateTime)); // 使用 AutoGenerateColumnAttribute 设置显示名称示例 - context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), new KeyValuePair[] { new(nameof(AutoGenerateColumnAttribute.Text), FooLocalizer[nameof(Foo.DateTime)].Value) }); + context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), [ + new KeyValuePair(nameof(AutoGenerateColumnAttribute.Text), + FooLocalizer[nameof(Foo.DateTime)].Value) + ]); } else if (propertyName == nameof(Foo.Name)) { @@ -70,96 +101,84 @@ private void CreateContext() { col.Filterable = true; // 使用 DisplayAttribute 设置显示名称示例 - context.AddDisplayAttribute(nameof(Foo.Complete), new KeyValuePair[] { new(nameof(DisplayAttribute.Name), FooLocalizer[nameof(Foo.Complete)].Value) }); + context.AddDisplayAttribute(nameof(Foo.Complete), [ + new KeyValuePair(nameof(DisplayAttribute.Name), + FooLocalizer[nameof(Foo.Complete)].Value) + ]); } else if (propertyName == nameof(Foo.Id)) { col.Ignore = true; } }) + { + OnDeleteAsync = items => { - OnDeleteAsync = items => + // 数据源中移除 + foreach (var item in items) { - // 数据源中移除 - foreach (var item in items) + var id = item.GetValue(nameof(Foo.Id)); + if (id != null) { - var id = item.GetValue(nameof(Foo.Id)); - if (id != null) + var row = table.Rows.Find(id); + if (row != null) { - var row = UserData.Rows.Find(id); - if (row != null) - { - UserData.Rows.Remove(row); - } + table.Rows.Remove(row); } } + } - UserData.AcceptChanges(); - return Task.FromResult(true); - }, - OnChanged = args => + table.AcceptChanges(); + return Task.FromResult(true); + }, + OnChanged = args => + { + if (args.ChangedType == DynamicItemChangedType.Add) { - if (args.ChangedType == DynamicItemChangedType.Add) - { - var item = args.Items.First(); - item.SetValue(nameof(Foo.DateTime), DateTime.Today); - item.SetValue(nameof(Foo.Name), "新建值"); - } - - return Task.CompletedTask; + var item = args.Items.First(); + item.SetValue(nameof(Foo.DateTime), DateTime.Today); + item.SetValue(nameof(Foo.Name), "新建值"); } - }; - } - private void InitDataTable() - { - UserData.Columns.Add(nameof(Foo.Id), typeof(int)); - UserData.Columns.Add(nameof(Foo.DateTime), typeof(DateTime)); - UserData.Columns.Add(nameof(Foo.Name), typeof(string)); - UserData.Columns.Add(nameof(Foo.Count), typeof(int)); - UserData.PrimaryKey = - [ - UserData.Columns[0] - ]; - UserData.Columns[0].AutoIncrement = true; - Foo.GenerateFoo(FooLocalizer, 10).ForEach(f => - { - UserData.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); - }); - CreateContext(); - } + return Task.CompletedTask; + } + }; private Task OnAddColumn() { - if (!UserData.Columns.Contains(nameof(Foo.Complete))) + var table = _dataTableDynamicContext3!.DataTable; + if (!table.Columns.Contains(nameof(Foo.Complete))) { - UserData.Columns.Add(nameof(Foo.Complete), typeof(bool)); + table.Columns.Add(nameof(Foo.Complete), typeof(bool)); // 更新数据 var fs = Foo.GenerateFoo(FooLocalizer, 10); for (var i = 0; i < fs.Count; i++) { - UserData.Rows[i][nameof(Foo.Complete)] = fs[i].Complete; + table.Rows[i][nameof(Foo.Complete)] = fs[i].Complete; } - CreateContext(); + table.AcceptChanges(); + _dataTableDynamicContext3 = CreateContext(table); StateHasChanged(); } + return Task.CompletedTask; } private Task OnRemoveColumn() { - if (UserData.Columns.Contains(nameof(Foo.Complete))) + var table = _dataTableDynamicContext3!.DataTable; + if (table.Columns.Contains(nameof(Foo.Complete))) { - UserData.Columns.Remove(nameof(Foo.Complete)); - CreateContext(); + table.Columns.Remove(nameof(Foo.Complete)); + table.AcceptChanges(); + _dataTableDynamicContext3 = CreateContext(table); StateHasChanged(); } + return Task.CompletedTask; } - private DataTable PageDataTable { get; set; } = new(); - private int PageItems { get; set; } private int TotalCount { get; set; } @@ -168,55 +187,53 @@ private Task OnRemoveColumn() private int PageCount { get; set; } - [NotNull] - private List? PageFoos { get; set; } + private readonly List _pageData = []; + + private readonly DataTable _pageDataTable = new(); - private void InitPageDataTable() + private void CreatePageDataTable() { - PageDataTable.Columns.Add(nameof(Foo.Id), typeof(int)); - PageDataTable.Columns.Add(nameof(Foo.DateTime), typeof(DateTime)); - PageDataTable.Columns.Add(nameof(Foo.Name), typeof(string)); - PageDataTable.Columns.Add(nameof(Foo.Count), typeof(int)); - PageFoos = Foo.GenerateFoo(FooLocalizer, 80); - TotalCount = PageFoos.Count; + _pageDataTable.Columns.Add(nameof(Foo.Id), typeof(int)); + _pageDataTable.Columns.Add(nameof(Foo.DateTime), typeof(DateTime)); + _pageDataTable.Columns.Add(nameof(Foo.Name), typeof(string)); + _pageDataTable.Columns.Add(nameof(Foo.Count), typeof(int)); + _pageData.AddRange(Foo.GenerateFoo(FooLocalizer, 80)); + TotalCount = _pageData.Count; PageIndex = 1; PageItems = 2; PageCount = (int)Math.Ceiling(TotalCount / 2.0); - RebuildPageDataTable(); - RebuildPaginationDataTable(); - } - private void RebuildPageDataTable() - { - PageDataTable.Rows.Clear(); // 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页 - foreach (var f in PageFoos.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) + foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) { - PageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); + _pageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); } + _pageDataTable.AcceptChanges(); - PageDataTable.AcceptChanges(); + RebuildPaginationDataTable(); } - private void RebuildPaginationDataTable() { - PageDataTable.Rows.Clear(); + _pageDataTable.Rows.Clear(); // 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页 - foreach (var f in PageFoos.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) + foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) { - PageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); + _pageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); } - PageDataTable.AcceptChanges(); - DataTablePageDynamicContext = new DataTableDynamicContext(PageDataTable, (context, col) => + _pageDataTable.AcceptChanges(); + _dataTableDynamicContext4 = new DataTableDynamicContext(_pageDataTable, (context, col) => { var propertyName = col.GetFieldName(); if (propertyName == nameof(Foo.DateTime)) { context.AddRequiredAttribute(nameof(Foo.DateTime)); // 使用 AutoGenerateColumnAttribute 设置显示名称示例 - context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), new KeyValuePair[] { new(nameof(AutoGenerateColumnAttribute.Text), Localizer[nameof(Foo.DateTime)].Value) }); + context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), [ + new KeyValuePair(nameof(AutoGenerateColumnAttribute.Text), + Localizer[nameof(Foo.DateTime)].Value) + ]); } else if (propertyName == nameof(Foo.Name)) { @@ -237,9 +254,6 @@ private void RebuildPaginationDataTable() }); } - [NotNull] - private DataTableDynamicContext? DataTablePageDynamicContext { get; set; } - /// /// 点击页码处理函数 /// @@ -249,6 +263,7 @@ private Task OnPageLinkClick(int pageIndex) { PageIndex = pageIndex; RebuildPaginationDataTable(); + StateHasChanged(); return Task.CompletedTask; } From dad55f3a7e09103af7466d531aa9cdd184196662 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 10 Jun 2026 17:19:48 +0800 Subject: [PATCH 4/9] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E5=A4=9A=E8=AF=AD?= =?UTF-8?q?=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Table/TablesDynamic.razor | 8 +++----- .../Components/Samples/Table/TablesDynamic.razor.cs | 10 +++++----- src/BootstrapBlazor.Server/Locales/en-US.json | 4 ++++ src/BootstrapBlazor.Server/Locales/zh-CN.json | 4 ++++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor index 1540e74161d..ecc958e8f35 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor @@ -7,11 +7,9 @@

@Localizer["TablesDynamicDescription"]

-

注意事项:

-

DataTableDynamicContext 对象底层是通过 Emit 技术将 DataTable 行转成动态类型的,所以每创建一次 DataTableDynamicContext 底层就会创建一个动态程序集,所以实际项目中应该尽量避免重复创建动态程序集

-

可以通过设置 DataTableDynamicContext 属性 UseCache="false" 关闭内部的数据缓存,在自己的代码逻辑中更新 DataTableDynamicContextDataTable 属性,大大提高系统性能

- -

+

@Localizer["TablesDynamicNoteTitle"]

+

@((MarkupString)Localizer["TablesDynamicNoteP1"].Value)

+

@((MarkupString)Localizer["TablesDynamicNoteP2"].Value)

{ var item = args.Items.First(); item.SetValue(nameof(Foo.DateTime), DateTime.Today); - item.SetValue(nameof(Foo.Name), "新建值"); + item.SetValue(nameof(Foo.Name), Localizer["TablesDynamicNewValueText"].Value); } return Task.CompletedTask; @@ -232,20 +232,20 @@ private void RebuildPaginationDataTable() // 使用 AutoGenerateColumnAttribute 设置显示名称示例 context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), [ new KeyValuePair(nameof(AutoGenerateColumnAttribute.Text), - Localizer[nameof(Foo.DateTime)].Value) + FooLocalizer[nameof(Foo.DateTime)].Value) ]); } else if (propertyName == nameof(Foo.Name)) { - context.AddRequiredAttribute(nameof(Foo.Name), Localizer["Name.Required"]); + context.AddRequiredAttribute(nameof(Foo.Name), FooLocalizer["Name.Required"]); // 使用 Text 设置显示名称示例 - col.Text = Localizer[nameof(Foo.Name)]; + col.Text = FooLocalizer[nameof(Foo.Name)]; } else if (propertyName == nameof(Foo.Count)) { context.AddRequiredAttribute(nameof(Foo.Count)); // 使用 DisplayNameAttribute 设置显示名称示例 - context.AddDisplayNameAttribute(nameof(Foo.Count), Localizer[nameof(Foo.Count)].Value); + context.AddDisplayNameAttribute(nameof(Foo.Count), FooLocalizer[nameof(Foo.Count)].Value); } else if (propertyName == nameof(Foo.Id)) { diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index fb60e16b823..6662ed72923 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -4835,6 +4835,10 @@ "TablesDynamicEditDescription": "By setting the OnChanged callback method of the DataTableDynamicContext instance, the value is automatically set when a new row is created", "TablesDynamicEditIntro": "Add editing and maintenance functions", "TablesDynamicEditTitle": "Edit function", + "TablesDynamicNewValueText": "New Value", + "TablesDynamicNoteP1": "The DataTableDynamicContext object internally uses Emit to convert DataTable rows into dynamic types, so every time a DataTableDynamicContext is created a dynamic assembly is generated under the hood. In real projects you should avoid creating dynamic assemblies repeatedly", + "TablesDynamicNoteP2": "You can set the UseCache=\"false\" property of DataTableDynamicContext to disable the internal data cache, and update the DataTable property of DataTableDynamicContext in your own code logic to greatly improve system performance", + "TablesDynamicNoteTitle": "Notes:", "TablesDynamicPageIntro": "Use Pagination component", "TablesDynamicPageTitle": "Pagination", "TablesDynamicTitle": "Table Dynamic" diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index a936bc37cbc..c65b68bf1f1 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -4835,6 +4835,10 @@ "TablesDynamicEditDescription": "通过设置 DataTableDynamicContext 实例的 OnChanged 回调方法,新建行时自动设置值", "TablesDynamicEditIntro": "增加编辑维护功能", "TablesDynamicEditTitle": "编辑功能", + "TablesDynamicNewValueText": "新建值", + "TablesDynamicNoteP1": "DataTableDynamicContext 对象底层是通过 Emit 技术将 DataTable 行转成动态类型的,所以每创建一次 DataTableDynamicContext 底层就会创建一个动态程序集,所以实际项目中应该尽量避免重复创建动态程序集", + "TablesDynamicNoteP2": "可以通过设置 DataTableDynamicContext 属性 UseCache=\"false\" 关闭内部的数据缓存,在自己的代码逻辑中更新 DataTableDynamicContextDataTable 属性,大大提高系统性能", + "TablesDynamicNoteTitle": "注意事项:", "TablesDynamicPageIntro": "通过与 Pagination 组件配合实现分页功能", "TablesDynamicPageTitle": "分页", "TablesDynamicTitle": "Table 表格" From 4897c4ae60cbc81824f73dd2833572d76b81e994 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 10 Jun 2026 17:48:19 +0800 Subject: [PATCH 5/9] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Samples/Table/TablesDynamic.razor.cs | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs index be759c48f2b..0b9c268e081 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs @@ -66,7 +66,7 @@ private void InitDataTableContext() _dataTableDynamicContext3 = CreateContext(table); CreatePageDataTable(); - RebuildPaginationDataTable(); + CreatePageDataContext(); } private static bool ModelEqualityComparer(IDynamicObject x, IDynamicObject y) => @@ -209,20 +209,10 @@ private void CreatePageDataTable() _pageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); } _pageDataTable.AcceptChanges(); - - RebuildPaginationDataTable(); } - private void RebuildPaginationDataTable() + private void CreatePageDataContext() { - _pageDataTable.Rows.Clear(); - // 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页 - foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) - { - _pageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); - } - - _pageDataTable.AcceptChanges(); _dataTableDynamicContext4 = new DataTableDynamicContext(_pageDataTable, (context, col) => { var propertyName = col.GetFieldName(); @@ -251,7 +241,24 @@ private void RebuildPaginationDataTable() { col.Ignore = true; } - }); + }) + { + UseCache = false + }; + } + + private void UpdatePageDataTableContext() + { + var table = _dataTableDynamicContext4!.DataTable; + table.Rows.Clear(); + + // 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页 + foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) + { + table.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); + } + + table.AcceptChanges(); } /// @@ -262,7 +269,7 @@ private void RebuildPaginationDataTable() private Task OnPageLinkClick(int pageIndex) { PageIndex = pageIndex; - RebuildPaginationDataTable(); + UpdatePageDataTableContext(); StateHasChanged(); return Task.CompletedTask; From a44d1940173c31fe7d3146b4a2e5f220103508de Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 10 Jun 2026 18:20:00 +0800 Subject: [PATCH 6/9] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Samples/Table/TablesDynamic.razor | 24 +++++++++++++++++++ .../Samples/Table/TablesDynamic.razor.cs | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor index ecc958e8f35..4ed1eb23cc6 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor @@ -10,6 +10,30 @@

@Localizer["TablesDynamicNoteTitle"]

@((MarkupString)Localizer["TablesDynamicNoteP1"].Value)

@((MarkupString)Localizer["TablesDynamicNoteP2"].Value)

+

可以查看分页表格示例代码,通过 CreatePageDataContext 创建 DataTableDynamicContext 实例,点击分页的时候仅更新数据,不需要重新创建 DataTableDynamicContext 实例

+
private void CreatePageDataContext()
+{
+    _dataTableDynamicContext4 = new DataTableDynamicContext(_pageDataTable, (context, col) =>
+    {
+        var propertyName = col.GetFieldName();
+    })
+    {
+        UseCache = false
+    };
+}
+
+private void UpdatePageDataContext()
+{
+    var table = _dataTableDynamicContext4!.DataTable;
+    table.Rows.Clear();
+
+    foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList())
+    {
+        table.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
+    }
+
+    table.AcceptChanges();
+}
Date: Thu, 11 Jun 2026 09:02:23 +0800 Subject: [PATCH 7/9] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Table/TablesDynamic.razor | 2 +- src/BootstrapBlazor.Server/Locales/en-US.json | 1 + src/BootstrapBlazor.Server/Locales/zh-CN.json | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor index 4ed1eb23cc6..6a8ea58b46c 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor @@ -10,7 +10,7 @@

@Localizer["TablesDynamicNoteTitle"]

@((MarkupString)Localizer["TablesDynamicNoteP1"].Value)

@((MarkupString)Localizer["TablesDynamicNoteP2"].Value)

-

可以查看分页表格示例代码,通过 CreatePageDataContext 创建 DataTableDynamicContext 实例,点击分页的时候仅更新数据,不需要重新创建 DataTableDynamicContext 实例

+

@((MarkupString)Localizer["TablesDynamicNoteP3"].Value)

private void CreatePageDataContext()
 {
     _dataTableDynamicContext4 = new DataTableDynamicContext(_pageDataTable, (context, col) =>
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json
index 6662ed72923..b09fbe5fc01 100644
--- a/src/BootstrapBlazor.Server/Locales/en-US.json
+++ b/src/BootstrapBlazor.Server/Locales/en-US.json
@@ -4838,6 +4838,7 @@
     "TablesDynamicNewValueText": "New Value",
     "TablesDynamicNoteP1": "The DataTableDynamicContext object internally uses Emit to convert DataTable rows into dynamic types, so every time a DataTableDynamicContext is created a dynamic assembly is generated under the hood. In real projects you should avoid creating dynamic assemblies repeatedly",
     "TablesDynamicNoteP2": "You can set the UseCache=\"false\" property of DataTableDynamicContext to disable the internal data cache, and update the DataTable property of DataTableDynamicContext in your own code logic to greatly improve system performance",
+    "TablesDynamicNoteP3": "You can refer to the pagination table sample code. Use CreatePageDataContext to create the DataTableDynamicContext instance. When clicking the pager, only the data is updated, and there is no need to recreate the DataTableDynamicContext instance",
     "TablesDynamicNoteTitle": "Notes:",
     "TablesDynamicPageIntro": "Use Pagination component",
     "TablesDynamicPageTitle": "Pagination",
diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json
index c65b68bf1f1..a73b1138679 100644
--- a/src/BootstrapBlazor.Server/Locales/zh-CN.json
+++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json
@@ -4838,6 +4838,7 @@
     "TablesDynamicNewValueText": "新建值",
     "TablesDynamicNoteP1": "DataTableDynamicContext 对象底层是通过 Emit 技术将 DataTable 行转成动态类型的,所以每创建一次 DataTableDynamicContext 底层就会创建一个动态程序集,所以实际项目中应该尽量避免重复创建动态程序集",
     "TablesDynamicNoteP2": "可以通过设置 DataTableDynamicContext 属性 UseCache=\"false\" 关闭内部的数据缓存,在自己的代码逻辑中更新 DataTableDynamicContextDataTable 属性,大大提高系统性能",
+    "TablesDynamicNoteP3": "可以查看分页表格示例代码,通过 CreatePageDataContext 创建 DataTableDynamicContext 实例,点击分页的时候仅更新数据,不需要重新创建 DataTableDynamicContext 实例",
     "TablesDynamicNoteTitle": "注意事项:",
     "TablesDynamicPageIntro": "通过与 Pagination 组件配合实现分页功能",
     "TablesDynamicPageTitle": "分页",

From 1c6f147db3adaaf8afa1ecd882c0f19d918446ea Mon Sep 17 00:00:00 2001
From: Argo Zhang 
Date: Thu, 11 Jun 2026 09:11:01 +0800
Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E5=8F=98?=
 =?UTF-8?q?=E9=87=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Samples/Table/TablesDynamic.razor         | 12 +++---
 .../Samples/Table/TablesDynamic.razor.cs      | 40 ++++++++-----------
 2 files changed, 22 insertions(+), 30 deletions(-)

diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor
index 6a8ea58b46c..aa3ffb311da 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor
+++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor
@@ -27,7 +27,7 @@ private void UpdatePageDataContext()
     var table = _dataTableDynamicContext4!.DataTable;
     table.Rows.Clear();
 
-    foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList())
+    foreach (var f in _pageData.Skip((_pageIndex - 1) * _pageItems).Take(_pageItems).ToList())
     {
         table.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
     }
@@ -46,10 +46,10 @@ private void UpdatePageDataContext()
            Name="Edit">
     
@((MarkupString)Localizer["TablesDynamicEditDescription"].Value)
- @foreach (var item in SelectedItems) + @foreach (var item in _selectedItems) {
@item.GetValue(nameof(Foo.Name))
} @@ -63,10 +63,10 @@ private void UpdatePageDataContext() IsMultipleSelect="true" IsBordered="true" IsStriped="true" ShowToolbar="true" ShowExtendButtons="true"> - - @@ -77,5 +77,5 @@ private void UpdatePageDataContext() Introduction="@Localizer["TablesDynamicPageIntro"]" Name="Pagination">
- + diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs index fcec5145b0b..d42716b7024 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs @@ -16,12 +16,9 @@ public partial class TablesDynamic private DataTableDynamicContext? _dataTableDynamicContext2; private DataTableDynamicContext? _dataTableDynamicContext3; private DataTableDynamicContext? _dataTableDynamicContext4; - - private List SelectedItems { get; set; } = []; - - private string? ButtonAddColumnText { get; set; } - - private string? ButtonRemoveColumnText { get; set; } + private List _selectedItems = []; + private string? _buttonAddColumnText; + private string? _buttonRemoveColumnText; /// /// OnInitialized 方法 @@ -30,8 +27,8 @@ protected override void OnInitialized() { base.OnInitialized(); - ButtonAddColumnText ??= Localizer["TablesDynamicDynamicColButtonAddColumnText"]; - ButtonRemoveColumnText ??= Localizer["TablesDynamicDynamicColButtonRemoveColumnText"]; + _buttonAddColumnText ??= Localizer["TablesDynamicDynamicColButtonAddColumnText"]; + _buttonRemoveColumnText ??= Localizer["TablesDynamicDynamicColButtonRemoveColumnText"]; InitDataTableContext(); } @@ -179,16 +176,11 @@ private Task OnRemoveColumn() return Task.CompletedTask; } - private int PageItems { get; set; } - - private int TotalCount { get; set; } - - private int PageIndex { get; set; } = 1; - - private int PageCount { get; set; } - + private int _pageItems; + private int _totalCount; + private int _pageIndex = 1; + private int _pageCount; private readonly List _pageData = []; - private readonly DataTable _pageDataTable = new(); private void CreatePageDataTable() @@ -198,13 +190,13 @@ private void CreatePageDataTable() _pageDataTable.Columns.Add(nameof(Foo.Name), typeof(string)); _pageDataTable.Columns.Add(nameof(Foo.Count), typeof(int)); _pageData.AddRange(Foo.GenerateFoo(FooLocalizer, 80)); - TotalCount = _pageData.Count; - PageIndex = 1; - PageItems = 2; - PageCount = (int)Math.Ceiling(TotalCount / 2.0); + _totalCount = _pageData.Count; + _pageIndex = 1; + _pageItems = 2; + _pageCount = (int)Math.Ceiling(_totalCount / 2.0); // 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页 - foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) + foreach (var f in _pageData.Skip((_pageIndex - 1) * _pageItems).Take(_pageItems).ToList()) { _pageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); } @@ -253,7 +245,7 @@ private void UpdatePageDataContext() table.Rows.Clear(); // 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页 - foreach (var f in _pageData.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList()) + foreach (var f in _pageData.Skip((_pageIndex - 1) * _pageItems).Take(_pageItems).ToList()) { table.Rows.Add(f.Id, f.DateTime, f.Name, f.Count); } @@ -268,7 +260,7 @@ private void UpdatePageDataContext() /// private Task OnPageLinkClick(int pageIndex) { - PageIndex = pageIndex; + _pageIndex = pageIndex; UpdatePageDataContext(); StateHasChanged(); From 02dfa289fff961c202571aca698a101ab365cbf3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 11 Jun 2026 09:15:41 +0800 Subject: [PATCH 9/9] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Samples/Table/TablesDynamic.razor.cs | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs index d42716b7024..3821d350c6e 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs @@ -63,7 +63,7 @@ private void InitDataTableContext() _dataTableDynamicContext3 = CreateContext(table); CreatePageDataTable(); - CreatePageDataContext(); + _dataTableDynamicContext4 = CreatePageDataContext(); } private static bool ModelEqualityComparer(IDynamicObject x, IDynamicObject y) => @@ -193,7 +193,7 @@ private void CreatePageDataTable() _totalCount = _pageData.Count; _pageIndex = 1; _pageItems = 2; - _pageCount = (int)Math.Ceiling(_totalCount / 2.0); + _pageCount = (int)Math.Ceiling(_totalCount / (double)_pageItems); // 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页 foreach (var f in _pageData.Skip((_pageIndex - 1) * _pageItems).Take(_pageItems).ToList()) @@ -203,41 +203,38 @@ private void CreatePageDataTable() _pageDataTable.AcceptChanges(); } - private void CreatePageDataContext() + private DataTableDynamicContext CreatePageDataContext() => new DataTableDynamicContext(_pageDataTable, (context, col) => { - _dataTableDynamicContext4 = new DataTableDynamicContext(_pageDataTable, (context, col) => + var propertyName = col.GetFieldName(); + if (propertyName == nameof(Foo.DateTime)) { - var propertyName = col.GetFieldName(); - if (propertyName == nameof(Foo.DateTime)) - { - context.AddRequiredAttribute(nameof(Foo.DateTime)); - // 使用 AutoGenerateColumnAttribute 设置显示名称示例 - context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), [ - new KeyValuePair(nameof(AutoGenerateColumnAttribute.Text), + context.AddRequiredAttribute(nameof(Foo.DateTime)); + // 使用 AutoGenerateColumnAttribute 设置显示名称示例 + context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), [ + new KeyValuePair(nameof(AutoGenerateColumnAttribute.Text), FooLocalizer[nameof(Foo.DateTime)].Value) - ]); - } - else if (propertyName == nameof(Foo.Name)) - { - context.AddRequiredAttribute(nameof(Foo.Name), FooLocalizer["Name.Required"]); - // 使用 Text 设置显示名称示例 - col.Text = FooLocalizer[nameof(Foo.Name)]; - } - else if (propertyName == nameof(Foo.Count)) - { - context.AddRequiredAttribute(nameof(Foo.Count)); - // 使用 DisplayNameAttribute 设置显示名称示例 - context.AddDisplayNameAttribute(nameof(Foo.Count), FooLocalizer[nameof(Foo.Count)].Value); - } - else if (propertyName == nameof(Foo.Id)) - { - col.Ignore = true; - } - }) + ]); + } + else if (propertyName == nameof(Foo.Name)) { - UseCache = false - }; - } + context.AddRequiredAttribute(nameof(Foo.Name), FooLocalizer["Name.Required"]); + // 使用 Text 设置显示名称示例 + col.Text = FooLocalizer[nameof(Foo.Name)]; + } + else if (propertyName == nameof(Foo.Count)) + { + context.AddRequiredAttribute(nameof(Foo.Count)); + // 使用 DisplayNameAttribute 设置显示名称示例 + context.AddDisplayNameAttribute(nameof(Foo.Count), FooLocalizer[nameof(Foo.Count)].Value); + } + else if (propertyName == nameof(Foo.Id)) + { + col.Ignore = true; + } + }) + { + UseCache = false + }; private void UpdatePageDataContext() {