From 150197a88479f10e3052f4b1aa996beb3e044f6a Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Sat, 3 Feb 2024 22:10:35 +0800 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20Formatter=20=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=80=BC=E5=A2=9E=E5=8A=A0=E5=8F=AF=E4=B8=BA=E7=A9=BA=E6=A0=87?= =?UTF-8?q?=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Attributes/AutoGenerateColumnAttribute.cs | 2 +- .../Components/Display/Display.razor.cs | 2 +- .../Components/Table/ITableColumn.cs | 2 +- .../Components/Table/InternalTableColumn.cs | 29 +++++++------------ .../Components/Table/TableColumn.cs | 4 +-- .../Components/Upload/SingleUploadBase.cs | 2 +- test/UnitTest/Misc/MockTableColumn.cs | 2 +- test/UnitTest/Utils/JSModuleTest.cs | 2 -- 8 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/BootstrapBlazor/Attributes/AutoGenerateColumnAttribute.cs b/src/BootstrapBlazor/Attributes/AutoGenerateColumnAttribute.cs index 9642438d976..9bd5513976a 100644 --- a/src/BootstrapBlazor/Attributes/AutoGenerateColumnAttribute.cs +++ b/src/BootstrapBlazor/Attributes/AutoGenerateColumnAttribute.cs @@ -108,7 +108,7 @@ public class AutoGenerateColumnAttribute : AutoGenerateBaseAttribute, ITableColu /// /// 获得/设置 列格式化回调委托 /// - public Func>? Formatter { get; set; } + public Func>? Formatter { get; set; } /// /// 获得/设置 编辑模板 diff --git a/src/BootstrapBlazor/Components/Display/Display.razor.cs b/src/BootstrapBlazor/Components/Display/Display.razor.cs index fcebeaaed2f..5d92e7579e7 100644 --- a/src/BootstrapBlazor/Components/Display/Display.razor.cs +++ b/src/BootstrapBlazor/Components/Display/Display.razor.cs @@ -26,7 +26,7 @@ public partial class Display /// 获得/设置 异步格式化字符串 /// [Parameter] - public Func>? FormatterAsync { get; set; } + public Func>? FormatterAsync { get; set; } /// /// 获得/设置 格式化字符串 如时间类型设置 yyyy-MM-dd diff --git a/src/BootstrapBlazor/Components/Table/ITableColumn.cs b/src/BootstrapBlazor/Components/Table/ITableColumn.cs index bb2befcde7e..44b0fee6495 100644 --- a/src/BootstrapBlazor/Components/Table/ITableColumn.cs +++ b/src/BootstrapBlazor/Components/Table/ITableColumn.cs @@ -127,7 +127,7 @@ public interface ITableColumn : IEditorItem /// /// 获得/设置 列格式化回调委托 /// - Func>? Formatter { get; set; } + Func>? Formatter { get; set; } /// /// 获得/设置 文字对齐方式 默认为 Alignment.None diff --git a/src/BootstrapBlazor/Components/Table/InternalTableColumn.cs b/src/BootstrapBlazor/Components/Table/InternalTableColumn.cs index 72d25d600b9..a2e27450534 100644 --- a/src/BootstrapBlazor/Components/Table/InternalTableColumn.cs +++ b/src/BootstrapBlazor/Components/Table/InternalTableColumn.cs @@ -4,9 +4,15 @@ namespace BootstrapBlazor.Components; -class InternalTableColumn : ITableColumn +/// +/// 构造函数 +/// +/// 字段名称 +/// 字段类型 +/// 显示文字 +class InternalTableColumn(string fieldName, Type fieldType, string? fieldText = null) : ITableColumn { - private string FieldName { get; } + private string FieldName { get; } = fieldName; public bool Sortable { get; set; } @@ -72,13 +78,13 @@ class InternalTableColumn : ITableColumn /// public string? PlaceHolder { get; set; } - public Func>? Formatter { get; set; } + public Func>? Formatter { get; set; } public Alignment Align { get; set; } public bool ShowTips { get; set; } - public Type PropertyType { get; } + public Type PropertyType { get; } = fieldType; public bool Editable { get; set; } = true; @@ -89,7 +95,7 @@ class InternalTableColumn : ITableColumn public int Rows { get; set; } [NotNull] - public string? Text { get; set; } + public string? Text { get; set; } = fieldText; public RenderFragment? EditTemplate { get; set; } @@ -188,19 +194,6 @@ class InternalTableColumn : ITableColumn /// public bool IsMarkupString { get; set; } - /// - /// 构造函数 - /// - /// 字段名称 - /// 字段类型 - /// 显示文字 - public InternalTableColumn(string fieldName, Type fieldType, string? fieldText = null) - { - FieldName = fieldName; - PropertyType = fieldType; - Text = fieldText; - } - public string GetDisplayName() => Text; public string GetFieldName() => FieldName; diff --git a/src/BootstrapBlazor/Components/Table/TableColumn.cs b/src/BootstrapBlazor/Components/Table/TableColumn.cs index bf0a33338c3..d4962f722c5 100644 --- a/src/BootstrapBlazor/Components/Table/TableColumn.cs +++ b/src/BootstrapBlazor/Components/Table/TableColumn.cs @@ -236,7 +236,7 @@ public class TableColumn : BootstrapComponentBase, ITableColumn /// 获得/设置 列格式化回调委托 /// [Parameter] - public Func>? Formatter { get; set; } + public Func>? Formatter { get; set; } /// /// 获得/设置 显示模板 @@ -480,7 +480,7 @@ public string GetFieldName() express = member.Expression; } - if (fields.Any()) + if (fields.Count != 0) { fields.Reverse(); FieldName = string.Join(".", fields); diff --git a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs b/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs index 287716d87e4..4d8d334cdd5 100644 --- a/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs +++ b/src/BootstrapBlazor/Components/Upload/SingleUploadBase.cs @@ -40,7 +40,7 @@ protected virtual List GetUploadFiles() var ret = new List(); if (IsSingle) { - if (DefaultFileList?.Any() ?? false) + if (DefaultFileList != null && DefaultFileList.Count != 0) { ret.Add(DefaultFileList.First()); } diff --git a/test/UnitTest/Misc/MockTableColumn.cs b/test/UnitTest/Misc/MockTableColumn.cs index de987645424..c9b86987b84 100644 --- a/test/UnitTest/Misc/MockTableColumn.cs +++ b/test/UnitTest/Misc/MockTableColumn.cs @@ -76,7 +76,7 @@ internal class MockTableColumn : ITableColumn public string? FormatString { get; set; } - public Func>? Formatter { get; set; } + public Func>? Formatter { get; set; } public Alignment Align { get; set; } diff --git a/test/UnitTest/Utils/JSModuleTest.cs b/test/UnitTest/Utils/JSModuleTest.cs index 50a6cd215a9..24eb56d65bf 100644 --- a/test/UnitTest/Utils/JSModuleTest.cs +++ b/test/UnitTest/Utils/JSModuleTest.cs @@ -138,8 +138,6 @@ public ValueTask InvokeAsync(string identifier, CancellationToke { return ValueTask.FromResult(default!); } - - public ValueTask InvokeVoidAsync_JSDisconnected_Test() => throw new JSDisconnectedException("Test"); } private class MockJSDisconnectedObjectReference : IJSObjectReference From b12d8f197d9e37fcd95193d361f02ef5c588145c Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Sat, 3 Feb 2024 22:11:18 +0800 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20=E6=94=AF=E6=8C=81=20Formatter?= =?UTF-8?q?=20=E5=9B=9E=E8=B0=83=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Utils/Utility.cs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Utils/Utility.cs b/src/BootstrapBlazor/Utils/Utility.cs index 6a5319255ac..74983334796 100644 --- a/src/BootstrapBlazor/Utils/Utility.cs +++ b/src/BootstrapBlazor/Utils/Utility.cs @@ -408,8 +408,11 @@ public static void CreateDisplayByFieldType(this RenderTreeBuilder builder, IEdi builder.AddAttribute(4, nameof(Display.ShowLabelTooltip), item.ShowLabelTooltip); if (item is ITableColumn col) { - // TODO: 暂时不支持 Formatter 逻辑 - if (!string.IsNullOrEmpty(col.FormatString)) + if (col.Formatter != null) + { + builder.AddAttribute(5, nameof(Display.FormatterAsync), CreateFormatterCallaback(fieldType, col.Formatter)); + } + else if (!string.IsNullOrEmpty(col.FormatString)) { builder.AddAttribute(5, nameof(Display.FormatString), col.FormatString); } @@ -418,6 +421,20 @@ public static void CreateDisplayByFieldType(this RenderTreeBuilder builder, IEdi } } + private static object? CreateFormatterCallaback(Type type, Func> formatter) + { + var method = typeof(Utility).GetMethod(nameof(InvokeFormatterAsync), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(type); + var exp_p1 = Expression.Parameter(typeof(Func>)); + var body = Expression.Call(null, method, exp_p1); + var invoker = Expression.Lambda(body, exp_p1).Compile(); + return invoker!.DynamicInvoke(formatter); + } + + private static Func> InvokeFormatterAsync(Func> formatter) + { + return new Func>(v => formatter(v)); + } + /// /// RenderTreeBuilder 扩展方法 通过指定模型与属性生成编辑组件 /// @@ -528,7 +545,7 @@ public static void CreateComponentByFieldType(this RenderTreeBuilder builder, Co GroupName = d.GroupName }).ToList(); - private static object? GenerateValue(object model, string fieldName) => Utility.GetPropertyValue(model, fieldName); + private static object? GenerateValue(object model, string fieldName) => GetPropertyValue(model, fieldName); /// /// 通过指定类型实例获取属性 Lambda 表达式 From b75c35093824fef34e3dbde3137cd64272708285 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Sat, 3 Feb 2024 22:11:27 +0800 Subject: [PATCH 3/6] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=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 --- test/UnitTest/Utils/UtilityTest.cs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/UnitTest/Utils/UtilityTest.cs b/test/UnitTest/Utils/UtilityTest.cs index 3fbdc97d1c6..7b09ef49bcc 100644 --- a/test/UnitTest/Utils/UtilityTest.cs +++ b/test/UnitTest/Utils/UtilityTest.cs @@ -225,6 +225,31 @@ public void CreateDisplayByFieldType_FormatString() Assert.Equal($"
{dt:yyyy}
", cut.Markup); } + [Fact] + public void CreateDisplayByFieldType_Formatter() + { + var dt = DateTime.Now; + var editor = new MockTableColumn("DateTime", typeof(DateTime?)) + { + Formatter = new Func>(async v => + { + var ret = ""; + await Task.Delay(1); + if (v is DateTime d) + { + ret = $"{d:yyyyMMddhhmmss}"; + } + return ret; + }) + }; + var fragment = new RenderFragment(builder => builder.CreateDisplayByFieldType(editor, new Foo() { DateTime = dt })); + var cut = Context.Render(builder => builder.AddContent(0, fragment)); + cut.WaitForAssertion(() => + { + Assert.Equal($"
{dt:yyyyMMddhhmmss}
", cut.Markup); + }); + } + [Fact] public void CreateComponentByFieldType_Ok() { From 9d8ca781a89100e01fd69a8fb8bfcf0480ce6bf6 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Sat, 3 Feb 2024 22:29:09 +0800 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20GetFormatt?= =?UTF-8?q?erInvoker=20=E6=96=B9=E6=B3=95=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Services/CacheManager.cs | 26 ++++++++++++++++++-- src/BootstrapBlazor/Utils/Utility.cs | 16 +----------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/BootstrapBlazor/Services/CacheManager.cs b/src/BootstrapBlazor/Services/CacheManager.cs index bf659b6fcde..aa24907f4e3 100644 --- a/src/BootstrapBlazor/Services/CacheManager.cs +++ b/src/BootstrapBlazor/Services/CacheManager.cs @@ -627,7 +627,7 @@ public static Func, List, IEnumerable> GetSortListFunc #region Format public static Func GetFormatInvoker(Type type) { - var cacheKey = $"{nameof(GetFormatInvoker)}-{nameof(GetFormatLambda)}-{type.FullName}"; + var cacheKey = $"{nameof(GetFormatInvoker)}-{type.FullName}"; return Instance.GetOrCreate(cacheKey, entry => { entry.SetDynamicAssemblyPolicy(type); @@ -669,7 +669,7 @@ public static Func, List, IEnumerable> GetSortListFunc public static Func GetFormatProviderInvoker(Type type) { - var cacheKey = $"{nameof(GetFormatProviderInvoker)}-{nameof(GetFormatProviderLambda)}-{type.FullName}"; + var cacheKey = $"{nameof(GetFormatProviderInvoker)}-{type.FullName}"; return Instance.GetOrCreate(cacheKey, entry => { entry.SetDynamicAssemblyPolicy(type); @@ -697,5 +697,27 @@ public static Func, List, IEnumerable> GetSortListFunc return Expression.Lambda>(body, exp_p1, exp_p2); } } + + public static object GetFormatterInvoker(Type type, Func> formatter) + { + var cacheKey = $"{nameof(GetFormatterInvoker)}-{type.FullName}"; + return Instance.GetOrCreate(cacheKey, entry => + { + entry.SetDynamicAssemblyPolicy(type); + return GetFormatterInvokerLambda(type, formatter); + }); + + static object GetFormatterInvokerLambda(Type type, Func> formatter) + { + var method = typeof(CacheManager).GetMethod(nameof(InvokeFormatterAsync), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(type); + var exp_p1 = Expression.Parameter(typeof(Func>)); + var body = Expression.Call(null, method, exp_p1); + var invoker = Expression.Lambda>, object>>(body, exp_p1).Compile(); + return invoker(formatter); + } + } + + private static Func> InvokeFormatterAsync(Func> formatter) => new(v => formatter(v)); + #endregion } diff --git a/src/BootstrapBlazor/Utils/Utility.cs b/src/BootstrapBlazor/Utils/Utility.cs index 74983334796..4716469bf60 100644 --- a/src/BootstrapBlazor/Utils/Utility.cs +++ b/src/BootstrapBlazor/Utils/Utility.cs @@ -410,7 +410,7 @@ public static void CreateDisplayByFieldType(this RenderTreeBuilder builder, IEdi { if (col.Formatter != null) { - builder.AddAttribute(5, nameof(Display.FormatterAsync), CreateFormatterCallaback(fieldType, col.Formatter)); + builder.AddAttribute(5, nameof(Display.FormatterAsync), CacheManager.GetFormatterInvoker(fieldType, col.Formatter)); } else if (!string.IsNullOrEmpty(col.FormatString)) { @@ -421,20 +421,6 @@ public static void CreateDisplayByFieldType(this RenderTreeBuilder builder, IEdi } } - private static object? CreateFormatterCallaback(Type type, Func> formatter) - { - var method = typeof(Utility).GetMethod(nameof(InvokeFormatterAsync), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(type); - var exp_p1 = Expression.Parameter(typeof(Func>)); - var body = Expression.Call(null, method, exp_p1); - var invoker = Expression.Lambda(body, exp_p1).Compile(); - return invoker!.DynamicInvoke(formatter); - } - - private static Func> InvokeFormatterAsync(Func> formatter) - { - return new Func>(v => formatter(v)); - } - /// /// RenderTreeBuilder 扩展方法 通过指定模型与属性生成编辑组件 /// From 73bf8aebd0c6b4c697990dfd412025886892fba1 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Sat, 3 Feb 2024 22:35:42 +0800 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20FormatterI?= =?UTF-8?q?nvoke=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Services/CacheManager.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Services/CacheManager.cs b/src/BootstrapBlazor/Services/CacheManager.cs index aa24907f4e3..3498a560dfe 100644 --- a/src/BootstrapBlazor/Services/CacheManager.cs +++ b/src/BootstrapBlazor/Services/CacheManager.cs @@ -701,19 +701,19 @@ public static Func, List, IEnumerable> GetSortListFunc public static object GetFormatterInvoker(Type type, Func> formatter) { var cacheKey = $"{nameof(GetFormatterInvoker)}-{type.FullName}"; - return Instance.GetOrCreate(cacheKey, entry => + var invoker = Instance.GetOrCreate(cacheKey, entry => { entry.SetDynamicAssemblyPolicy(type); - return GetFormatterInvokerLambda(type, formatter); + return GetFormatterInvokerLambda(type).Compile(); }); + return invoker(formatter); - static object GetFormatterInvokerLambda(Type type, Func> formatter) + static Expression>, object>> GetFormatterInvokerLambda(Type type) { var method = typeof(CacheManager).GetMethod(nameof(InvokeFormatterAsync), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(type); var exp_p1 = Expression.Parameter(typeof(Func>)); var body = Expression.Call(null, method, exp_p1); - var invoker = Expression.Lambda>, object>>(body, exp_p1).Compile(); - return invoker(formatter); + return Expression.Lambda>, object>>(body, exp_p1); } } From b4c7ca56173a0e86de250854da1fe846f4e92731 Mon Sep 17 00:00:00 2001 From: Argo-AscioTech Date: Sat, 3 Feb 2024 22:37:13 +0800 Subject: [PATCH 6/6] =?UTF-8?q?test:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=B6=88=E9=99=A4=E8=AD=A6=E5=91=8A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Utils/UtilityTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/UnitTest/Utils/UtilityTest.cs b/test/UnitTest/Utils/UtilityTest.cs index 7b09ef49bcc..cdbe5506245 100644 --- a/test/UnitTest/Utils/UtilityTest.cs +++ b/test/UnitTest/Utils/UtilityTest.cs @@ -523,7 +523,7 @@ public void ConvertValueToString_Ok() var actual1 = Utility.ConvertValueToString(val); Assert.Equal("1.1,2,3.1", actual1); - var items = new List() { new SelectedItem("Test1", "Test1"), new SelectedItem("Test2", "Test2") }; + var items = new List() { new("Test1", "Test1"), new("Test2", "Test2") }; var actual2 = Utility.ConvertValueToString(items); Assert.Equal("Test1,Test2", actual2); @@ -722,6 +722,7 @@ private enum TestEnum Address } + [AttributeUsage(AttributeTargets.Property)] private class CatKeyAttribute : Attribute {