From fb97eaea68d180024a393c65faeca5ea9c0ee98e Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 23 Mar 2026 16:29:06 +0800 Subject: [PATCH 1/8] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=94=A8=E6=B3=95?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Table/TablesSearch.razor | 4 ++++ src/BootstrapBlazor.Server/Locales/en-US.json | 2 ++ src/BootstrapBlazor.Server/Locales/zh-CN.json | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor index 950f1be464b..c81ab72dee6 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor @@ -16,6 +16,10 @@ Name="SearchForm">

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

+
@((MarkupString)Localizer["SearchFormTips"].Value)
UseSearchForm is enabled and SearchItems is not provided, it will default to using TableColumn with Searchable=\"true\". You can customize the metadata through the SearchFormItemMetadata property in TableColumn", + "SearchFormDescItem1": "Customize metadata using the SearchFormItemMetadata property in TableColumn.", + "SearchFormDescItem2": "Customize the search item UI using the RenderContent method in the SearchFormItemMetadata parameter.", "SearchFormIntro": "Enable the search form feature by setting UseSearchForm=\"true\", and configure the search items within the form using SearchItems, suitable for scenarios with custom complex search conditions", "SearchFormTips": "Enabling UseSearchForm will prevent SearchModelSearchTemplate, CustomerSearchModel, and CustomerSearchTemplate from taking effect.", "SearchFormTitle": "Search Form", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 18b18e3d58f..947dc6c2f8e 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -5064,7 +5064,9 @@ "DisplayText5": "搜索表单", "EditModelTitle": "编辑测试数据窗口", "NamePlaceholder": "请输入姓名,50字以内", - "SearchFormDesc": "使用 UseSearchForm 开启搜索表单时未提供 SearchItems 默认尝试使用设置 Searchable=\"true\"TableColumn 进行构建,可以通过 TableColumn 中的 SearchFormItemMetadata 属性定制化元数据", + "SearchFormDesc": "使用 UseSearchForm 开启搜索表单时未提供 SearchItems 默认尝试使用设置 Searchable=\"true\"TableColumn 进行构建", + "SearchFormDescItem1": "通过 TableColumn 中的 SearchFormItemMetadata 属性定制化元数据", + "SearchFormDescItem2": "通过 SearchFormItemMetadata 参数中 RenderContent 方法自定义搜索项 UI", "SearchFormIntro": "通过设置 UseSearchForm=\"true\" 开启搜索表单功能,通过 SearchItems 配置搜索表单内搜索项,适用于自定义复杂搜索条件的场景", "SearchFormTips": "开启 UseSearchFormSearchModelSearchTemplateCustomerSearchModelCustomerSearchTemplate 均不生效", "SearchFormTitle": "搜索表单", From ebd87b8320e1f8ace03383b94b29baf8a50d68ce Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 23 Mar 2026 16:33:25 +0800 Subject: [PATCH 2/8] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/Table/TablesSearch.razor | 4 ++++ src/BootstrapBlazor.Server/Locales/en-US.json | 1 + src/BootstrapBlazor.Server/Locales/zh-CN.json | 1 + 3 files changed, 6 insertions(+) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor index c81ab72dee6..253ad5be32a 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesSearch.razor @@ -86,6 +86,10 @@
+ +
@((MarkupString)Localizer["SearchFormWarningTips"].Value)
+
+ diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 2d4d40f88f6..d38ad564a4a 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -5070,6 +5070,7 @@ "SearchFormIntro": "Enable the search form feature by setting UseSearchForm=\"true\", and configure the search items within the form using SearchItems, suitable for scenarios with custom complex search conditions", "SearchFormTips": "Enabling UseSearchForm will prevent SearchModel SearchTemplate, CustomerSearchModel, and CustomerSearchTemplate from taking effect.", "SearchFormTitle": "Search Form", + "SearchFormWarningTips": "BootstrapBlazor v10.4.2 introduced the UseSearchForm parameter, making the following examples obsolete. It is strongly recommended to use UseSearchForm.", "SearchTableGroupBoxText": "Search Criteria", "SearchTableIntro": "Set ShowSearch to display the query component, customize the search UI by setting the SearchTemplate template", "SearchTableLi1": "Enable no data display function by setting ShowEmpty=\"true\"", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 947dc6c2f8e..6c64be92c48 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -5070,6 +5070,7 @@ "SearchFormIntro": "通过设置 UseSearchForm=\"true\" 开启搜索表单功能,通过 SearchItems 配置搜索表单内搜索项,适用于自定义复杂搜索条件的场景", "SearchFormTips": "开启 UseSearchFormSearchModel SearchTemplate CustomerSearchModel CustomerSearchTemplate 均不生效", "SearchFormTitle": "搜索表单", + "SearchFormWarningTips": "BootstrapBlazor v10.4.2 版本后增加 UseSearchForm 参数后以下示例均可以不学习了,强烈推荐使用 UseSearchForm", "SearchTableGroupBoxText": "搜索条件", "SearchTableIntro": "设置 ShowSearch 显示查询组件,通过设置 SearchTemplate 模板自定义搜索 UI", "SearchTableLi1": "通过设置 ShowEmpty=\"true\" 开启无数据显示功能", From fbf65d8a6783bbd4ebbd0769ae232c6892e49616 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 23 Mar 2026 16:34:55 +0800 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=B7=B2?= =?UTF-8?q?=E5=BC=83=E7=94=A8=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Options/QueryPageOptions.cs | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/src/BootstrapBlazor/Options/QueryPageOptions.cs b/src/BootstrapBlazor/Options/QueryPageOptions.cs index b76089bc27c..46fa56f1754 100644 --- a/src/BootstrapBlazor/Options/QueryPageOptions.cs +++ b/src/BootstrapBlazor/Options/QueryPageOptions.cs @@ -81,42 +81,18 @@ public class QueryPageOptions /// public bool IsVirtualScroll { get; set; } - /// - /// 获得 通过列集合中的 列与 拼装 IFilterAction 集合 - /// Get IFilterAction collection assembled by columns in column collection and - /// - [Obsolete("This property is obsolete. Use Searches instead. 已过期,请使用 Searches 参数")] - [ExcludeFromCodeCoverage] - public List Searchs => Searches; - /// /// 获得 通过列集合中的 列与 拼装 IFilterAction 集合 /// Get IFilterAction collection assembled by columns in column collection and /// public List Searches { get; } = new(20); - /// - /// 获得 中过滤条件 模板中的条件请使用 获得 - /// Gets 中过滤条件 template中的条件请使用 Gets - /// - [Obsolete("This property is obsolete. Use CustomerSearches instead. 已过期,请使用 CustomerSearches 参数")] - [ExcludeFromCodeCoverage] - public List CustomerSearchs => CustomerSearches; - /// /// 获得 中过滤条件 模板中的条件请使用 获得 /// Get filter conditions in please use to get conditions in template /// public List CustomerSearches { get; } = new(20); - /// - /// 获得 中过滤条件 - /// Get filter conditions in - /// - [Obsolete("This property is obsolete. Use AdvanceSearches instead. 已过期,请使用 AdvanceSearches 参数")] - [ExcludeFromCodeCoverage] - public List AdvanceSearchs => AdvanceSearches; - /// /// 获得 中过滤条件 /// Get filter conditions in @@ -129,15 +105,6 @@ public class QueryPageOptions /// public List Filters { get; } = new(20); - /// - /// 获得 是否为首次查询 默认 false - /// Get whether is first query default false - /// - /// 组件首次查询数据时为 true - [Obsolete("This property is obsolete. Use IsFirstQuery. 已弃用单词拼写错误,请使用 IsFirstQuery")] - [ExcludeFromCodeCoverage] - public bool IsFristQuery { get => IsFirstQuery; set => IsFirstQuery = value; } - /// /// 获得 是否为首次查询 默认 false /// Get whether is first query default false From 5eb79cebad41405235d3b0dea654bd4f01d0ba06 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 23 Mar 2026 16:59:18 +0800 Subject: [PATCH 4/8] =?UTF-8?q?refactor:=20=E9=87=8D=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dynamic/DataTableDynamicContext.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs b/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs index 847d91b3183..fa3c9fe4470 100644 --- a/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs +++ b/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs @@ -40,7 +40,7 @@ public class DataTableDynamicContext : DynamicObjectContext /// 负责将 DataRow 与 Items 关联起来方便查找提高效率 /// Responsible for associating DataRow with Items to facilitate lookup and improve efficiency /// - private ConcurrentDictionary Caches { get; } = new(); + private ConcurrentDictionary _dataCache = new(); /// /// 添加行回调委托 @@ -136,7 +136,7 @@ public override IEnumerable GetItems() private List BuildItems() { - Caches.Clear(); + _dataCache.Clear(); var ret = new List(); foreach (DataRow row in DataTable.Rows) { @@ -155,7 +155,7 @@ private List BuildItems() d.Row = row; d.DynamicObjectPrimaryKey = Guid.NewGuid(); - Caches.TryAdd(d.DynamicObjectPrimaryKey, (d, row)); + _dataCache.TryAdd(d.DynamicObjectPrimaryKey, (d, row)); ret.Add(d); } } @@ -203,7 +203,7 @@ public override async Task AddAsync(IEnumerable selectedItems) var indexOfRow = 0; var item = selectedItems.FirstOrDefault(); - if (item != null && Caches.TryGetValue(item.DynamicObjectPrimaryKey, out var c)) + if (item != null && _dataCache.TryGetValue(item.DynamicObjectPrimaryKey, out var c)) { indexOfRow = DataTable.Rows.IndexOf(c.Row); } @@ -232,7 +232,7 @@ public override async Task AddAsync(IEnumerable selectedItems) Items?.Insert(indexOfRow, dynamicObject); // 缓存更新数据 - Caches.TryAdd(dynamicObject.DynamicObjectPrimaryKey, (dynamicObject, row)); + _dataCache.TryAdd(dynamicObject.DynamicObjectPrimaryKey, (dynamicObject, row)); } } @@ -252,7 +252,7 @@ public override async Task DeleteAsync(IEnumerable items) var changed = false; foreach (var item in items) { - if (Caches.TryGetValue(item.DynamicObjectPrimaryKey, out var row)) + if (_dataCache.TryGetValue(item.DynamicObjectPrimaryKey, out var row)) { changed = true; @@ -260,7 +260,7 @@ public override async Task DeleteAsync(IEnumerable items) DataTable.Rows.Remove(row.Row); // 清理缓存 - Caches.TryRemove(item.DynamicObjectPrimaryKey, out _); + _dataCache.TryRemove(item.DynamicObjectPrimaryKey, out _); // 清理 Table 组件数据源 Items?.Remove(item); @@ -289,7 +289,7 @@ public override async Task DeleteAsync(IEnumerable items) private Task OnCellValueChanged(IDynamicObject item, ITableColumn column, object? val) { // 更新内部 DataRow - if (Caches.TryGetValue(item.DynamicObjectPrimaryKey, out var cacheItem)) + if (_dataCache.TryGetValue(item.DynamicObjectPrimaryKey, out var cacheItem)) { cacheItem.Row[column.GetFieldName()] = val; Items = null; From 3e392f565b785ba7c687f9976ad2af660a4da471 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 24 Mar 2026 11:50:48 +0800 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E9=98=B2=E6=AD=A2=E7=94=9F=E6=88=90=E8=BF=87=E5=A4=9A?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dynamic/DataTableDynamicContext.cs | 15 ++++++++++++++- src/BootstrapBlazor/Services/CacheManager.cs | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs b/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs index fa3c9fe4470..49d97b1c10c 100644 --- a/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs +++ b/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs @@ -90,7 +90,20 @@ public DataTableDynamicContext(DataTable table, Action().Select(static c => $"{c.ColumnName}:{c.DataType.FullName}")); + var cacheKey = $"BootstrapBlazor-{nameof(DataTableDynamicContext)}-{columnNames}"; + var dynamicType = CacheManager.GetDynamicObjectTypeByName(cacheKey, cols, OnColumnCreating, out var cached); + + // 缓存命中时仍需调用回调以处理列属性 + if (cached && AddAttributesCallback != null) + { + foreach (var col in cols) + { + AddAttributesCallback?.Invoke(this, col); + } + } + return dynamicType ?? throw new InvalidOperationException(); } } diff --git a/src/BootstrapBlazor/Services/CacheManager.cs b/src/BootstrapBlazor/Services/CacheManager.cs index 0d459357f23..400e72a2e7c 100644 --- a/src/BootstrapBlazor/Services/CacheManager.cs +++ b/src/BootstrapBlazor/Services/CacheManager.cs @@ -10,6 +10,7 @@ using System.Globalization; using System.Linq.Expressions; using System.Reflection; +using System.Reflection.Emit; #if NET8_0_OR_GREATER using System.Runtime.CompilerServices; @@ -764,4 +765,18 @@ public static object GetFormatterInvoker(Type type, Func> private static Func> InvokeFormatterAsync(Func> formatter) => new(v => formatter(v)); #endregion + + internal static Type? GetDynamicObjectTypeByName(string key, IEnumerable cols, Func>? creatingCallback, out bool cached) + { + var created = false; + var type = Instance.GetOrCreate(key, _ => + { + created = true; + return EmitHelper.CreateTypeByName($"BootstrapBlazor_{nameof(DataTableDynamicContext)}_{key}", cols, typeof(DataTableDynamicObject), creatingCallback); + }); + + // 是否从缓存中获取到的值 + cached = !created; + return type; + } } From 3b03c5ea518cb6cf4305c1f1285da9e04d619cd4 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 24 Mar 2026 11:50:56 +0800 Subject: [PATCH 6/8] =?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 --- .../Components/Samples/Table/TablesDynamic.razor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs index 9950d0bdd75..adadea24510 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Table/TablesDynamic.razor.cs @@ -47,6 +47,8 @@ private void CreateContext() DataTableDynamicContext = new DataTableDynamicContext(UserData, (context, col) => { var propertyName = col.GetFieldName(); + // 使用 Text 设置显示名称示例 + col.Text = FooLocalizer[propertyName]; if (propertyName == nameof(Foo.DateTime)) { context.AddRequiredAttribute(nameof(Foo.DateTime)); @@ -56,8 +58,6 @@ private void CreateContext() 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)) { From 8fb0d8f220564379d20d96c83b8bb01f52679890 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 24 Mar 2026 13:22:36 +0800 Subject: [PATCH 7/8] chore: bump version 10.5.0-beta02 --- src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 0c5e8763a59..66d50a785ea 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 10.5.0-beta01 + 10.5.0-beta02 From a326e6aebaf87310fee2a05ff7f95ea4719f77cd Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Tue, 24 Mar 2026 13:38:10 +0800 Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20readonly?= =?UTF-8?q?=20=E5=85=B3=E9=94=AE=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs b/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs index 49d97b1c10c..63c002629fa 100644 --- a/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs +++ b/src/BootstrapBlazor/Dynamic/DataTableDynamicContext.cs @@ -40,7 +40,7 @@ public class DataTableDynamicContext : DynamicObjectContext /// 负责将 DataRow 与 Items 关联起来方便查找提高效率 /// Responsible for associating DataRow with Items to facilitate lookup and improve efficiency /// - private ConcurrentDictionary _dataCache = new(); + private readonly ConcurrentDictionary _dataCache = new(); /// /// 添加行回调委托