From 3659fb6de31c5ac7490da1eba0e5194bbcee099f Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:30:38 +0800 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=E5=BC=83?= =?UTF-8?q?=E7=94=A8=E6=A0=87=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs b/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs index b11835927ba..3edb290eae6 100644 --- a/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs +++ b/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs @@ -70,6 +70,14 @@ public partial class AutoFill [Parameter] public Func>>? OnCustomFilter { get; set; } + /// + /// 获得/设置 候选项模板 默认 null + /// + [Parameter] + [Obsolete("已弃用,请使用 ItemTemplate 代替")] + [ExcludeFromCodeCoverage] + public RenderFragment? Template { get => ItemTemplate; set => ItemTemplate = value; } + [Inject] [NotNull] private IStringLocalizer? Localizer { get; set; } From 66bf9550a9c5abba52fe483182d72849cb0284ca Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:31:06 +0800 Subject: [PATCH 2/9] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Search/Search.razor | 5 ++- .../Components/Search/Search.razor.cs | 38 ++++++++++++++----- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/BootstrapBlazor/Components/Search/Search.razor b/src/BootstrapBlazor/Components/Search/Search.razor index a9fb830cbae..e5bdd549224 100644 --- a/src/BootstrapBlazor/Components/Search/Search.razor +++ b/src/BootstrapBlazor/Components/Search/Search.razor @@ -1,5 +1,6 @@ @namespace BootstrapBlazor.Components -@inherits PopoverCompleteBase +@typeparam TValue +@inherits PopoverCompleteBase
@@ -27,7 +28,7 @@ } else { -
@item
+
@GetDisplayText(item)
} } diff --git a/src/BootstrapBlazor/Components/Search/Search.razor.cs b/src/BootstrapBlazor/Components/Search/Search.razor.cs index 6c070a20648..f453748b60c 100644 --- a/src/BootstrapBlazor/Components/Search/Search.razor.cs +++ b/src/BootstrapBlazor/Components/Search/Search.razor.cs @@ -10,7 +10,7 @@ namespace BootstrapBlazor.Components; /// /// Search 组件 /// -public partial class Search +public partial class Search { /// /// 获得/设置 是否显示清除按钮 默认为 false 不显示 @@ -77,17 +77,24 @@ public partial class Search /// 获得/设置 点击搜索按钮时回调委托 /// [Parameter] - public Func>>? OnSearch { get; set; } + public Func>>? OnSearch { get; set; } + + /// + /// 获得/设置 通过模型获得显示文本方法 默认使用 ToString 重载方法 + /// + [Parameter] + [NotNull] + public Func? OnGetDisplayText { get; set; } /// /// 获得/设置 点击清空按钮时回调委托 /// [Parameter] - public Func? OnClear { get; set; } + public Func? OnClear { get; set; } [Inject] [NotNull] - private IStringLocalizer? Localizer { get; set; } + private IStringLocalizer>? Localizer { get; set; } /// /// @@ -105,7 +112,7 @@ public partial class Search /// 获得/设置 UI 呈现数据集合 /// [NotNull] - private List? FilterItems { get; set; } + private List? FilterItems { get; set; } /// /// @@ -139,6 +146,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) } } + private string? _displayText; private bool _show; /// /// 点击搜索按钮时触发此方法 @@ -151,12 +159,12 @@ private async Task OnSearchClick() ButtonIcon = SearchButtonLoadingIcon; await Task.Yield(); - var items = await OnSearch(Value); + var items = await OnSearch(_displayText); FilterItems = items.ToList(); ButtonIcon = SearchButtonIcon; if (IsAutoClearAfterSearch) { - Value = ""; + _displayText = ""; } if (IsOnInputTrigger == false) { @@ -174,12 +182,22 @@ private async Task OnClearClick() { if (OnClear != null) { - await OnClear(Value); + await OnClear(_displayText); } - CurrentValue = ""; + _displayText = ""; FilterItems = []; } + private string? GetDisplayText(TValue item) + { + var displayText = item?.ToString(); + if (OnGetDisplayText != null) + { + displayText = OnGetDisplayText(item); + } + return displayText; + } + /// /// TriggerOnChange 方法 /// @@ -188,7 +206,7 @@ private async Task OnClearClick() [JSInvokable] public async Task TriggerOnChange(string val, bool search = true) { - CurrentValue = val; + _displayText = val; if (search) { From 97ca5263d4e6324705aa72b9e23e6ea3b759d2f5 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:38:46 +0800 Subject: [PATCH 3/9] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs b/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs index 3edb290eae6..4272cac2715 100644 --- a/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs +++ b/src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs @@ -74,7 +74,7 @@ public partial class AutoFill /// 获得/设置 候选项模板 默认 null /// [Parameter] - [Obsolete("已弃用,请使用 ItemTemplate 代替")] + [Obsolete("已弃用,请使用 ItemTemplate 代替;Deprecated please use ItemTemplate parameter")] [ExcludeFromCodeCoverage] public RenderFragment? Template { get => ItemTemplate; set => ItemTemplate = value; } From ad4c969cdb673690af449b07e050f3aa366c9bcb Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:38:57 +0800 Subject: [PATCH 4/9] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E5=8F=AF?= =?UTF-8?q?=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Search/Search.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Search/Search.razor.cs b/src/BootstrapBlazor/Components/Search/Search.razor.cs index f453748b60c..9b9854f98a0 100644 --- a/src/BootstrapBlazor/Components/Search/Search.razor.cs +++ b/src/BootstrapBlazor/Components/Search/Search.razor.cs @@ -146,7 +146,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) } } - private string? _displayText; + private string _displayText = ""; private bool _show; /// /// 点击搜索按钮时触发此方法 From 08de3b33dab2e2b61fbba1d1cd16301e24d9c760 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:40:14 +0800 Subject: [PATCH 5/9] =?UTF-8?q?refactor:=20=E4=BD=BF=E7=94=A8=20ItemTempla?= =?UTF-8?q?te=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/AutoFills.razor | 12 ++++++------ .../Components/Samples/InputGroups.razor | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor b/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor index e77487641d0..52221f3d69e 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/AutoFills.razor @@ -10,7 +10,7 @@ @((MarkupString)@Localizer["NormalDesc"].Value) - +
@@ -32,7 +32,7 @@
@((MarkupString)Localizer["CustomFilterDesc"].Value)
- +
@@ -54,7 +54,7 @@ @((MarkupString)@Localizer["ShowDropdownListOnFocusDesc"].Value)
- +
diff --git a/src/BootstrapBlazor.Server/Components/Samples/InputGroups.razor b/src/BootstrapBlazor.Server/Components/Samples/InputGroups.razor index 13051e8819e..4de65623fb9 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/InputGroups.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/InputGroups.razor @@ -89,7 +89,7 @@ - +
From 24ca37824773e8f1d7c6750d85244b60d410c1a2 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:40:27 +0800 Subject: [PATCH 6/9] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA=E4=BE=8B?= =?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/Pages/Coms.razor.cs | 4 ++-- .../Components/Samples/Searches.razor | 13 +++++++++++++ .../Components/Samples/Searches.razor.cs | 8 ++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs index e154a99d0e7..662ec3b8fa4 100644 --- a/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Pages/Coms.razor.cs @@ -14,9 +14,9 @@ public sealed partial class Coms private string? SearchText { get; set; } - private Task> OnSearch(string searchText) + private Task> OnSearch(string searchText) { SearchText = searchText; - return Task.FromResult>(ComponentItems.Where(i => i.Contains(searchText, StringComparison.OrdinalIgnoreCase))); + return Task.FromResult>(ComponentItems.Where(i => i.Contains(searchText, StringComparison.OrdinalIgnoreCase)).ToList()); } } diff --git a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor index ac4aea7997b..0616d940bfb 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor @@ -35,6 +35,19 @@ + + + +
@context.Name
+
@context.Address
+
+
+
+ diff --git a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs index 02002766368..46667adb18b 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs @@ -54,6 +54,14 @@ private Task> OnKeyboardSearch(string searchText) private Foo Model { get; set; } = new Foo() { Name = "" }; + private static string? GetDisplayText(Foo foo) => foo.Name; + + private static async Task> OnSearchFoo(string searchText) + { + await Task.Delay(100); + return Enumerable.Range(1, 10).Select(i => new Foo() { Name = $"{searchText}-{i}", Address = $"Address - 10{i}" }).ToList(); + } + /// /// 获得属性方法 /// From 2c5f1929c5e2cf56ddbd4a22a3d6b5460e8124bd Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:54:05 +0800 Subject: [PATCH 7/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 --- test/UnitTest/Components/AutoFillTest.cs | 2 +- test/UnitTest/Components/SearchTest.cs | 43 +++++++++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/test/UnitTest/Components/AutoFillTest.cs b/test/UnitTest/Components/AutoFillTest.cs index b33e86fabfa..b04ebdda406 100644 --- a/test/UnitTest/Components/AutoFillTest.cs +++ b/test/UnitTest/Components/AutoFillTest.cs @@ -163,7 +163,7 @@ public void OnGetDisplayText_Ok() { pb.Add(a => a.Value, Model); pb.Add(a => a.Items, Items); - pb.Add(a => a.OnGetDisplayText, foo => foo.Name ?? ""); + pb.Add(a => a.OnGetDisplayText, foo => foo.Name); }); var input = cut.Find("input"); Assert.Equal("张三 1000", input.Attributes["value"]?.Value); diff --git a/test/UnitTest/Components/SearchTest.cs b/test/UnitTest/Components/SearchTest.cs index 2c874cc3531..8edd15d0479 100644 --- a/test/UnitTest/Components/SearchTest.cs +++ b/test/UnitTest/Components/SearchTest.cs @@ -10,7 +10,7 @@ public class SearchTest : BootstrapBlazorTestBase [Fact] public void Items_Ok() { - var cut = Context.RenderComponent(); + var cut = Context.RenderComponent>(); Assert.Contains("
() { "test1", "test2" }; - var cut = Context.RenderComponent(pb => + var items = new List() { new() { Name = "test1", Address = "Address 1" }, new() { Name = "test2", Address = "Address 2" } }; + var cut = Context.RenderComponent>(pb => { pb.Add(a => a.ItemTemplate, item => builder => { - builder.AddContent(0, $"Template-{item}"); + builder.AddContent(0, $"Template-{item.Name}-{item.Address}"); }); pb.Add(a => a.OnSearch, async v => { @@ -43,14 +43,35 @@ public async Task ItemTemplate_Ok() await cut.InvokeAsync(() => cut.Instance.TriggerOnChange("t")); await Task.Delay(20); - Assert.Contains("Template-test1", cut.Markup); - Assert.Contains("Template-test2", cut.Markup); + Assert.Contains("Template-test1-Address 1", cut.Markup); + Assert.Contains("Template-test2-Address 2", cut.Markup); + } + + [Fact] + public async Task OnGetDisplayText_Ok() + { + var items = new List() { new() { Name = "test1", Address = "Address 1" }, new() { Name = "test2", Address = "Address 2" } }; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.OnSearch, async v => + { + await Task.Delay(1); + return items; + }); + pb.Add(a => a.OnGetDisplayText, foo => foo.Name); + }); + + await cut.InvokeAsync(() => cut.Instance.TriggerOnChange("t")); + await Task.Delay(20); + + Assert.Contains("test1", cut.Markup); + Assert.Contains("test2", cut.Markup); } [Fact] public void IsOnInputTrigger_Ok() { - var cut = Context.RenderComponent(builder => + var cut = Context.RenderComponent>(builder => { builder.Add(s => s.IsOnInputTrigger, true); }); @@ -65,7 +86,7 @@ public async Task OnSearchClick_Ok() { string? val = null; var items = new List() { "test1", "test2" }; - var cut = Context.RenderComponent(builder => + var cut = Context.RenderComponent>(builder => { builder.Add(s => s.SearchButtonIcon, "fa-fw fa-solid fa-magnifying-glass"); builder.Add(s => s.SearchButtonText, "SearchText"); @@ -82,10 +103,6 @@ public async Task OnSearchClick_Ok() var menus = cut.FindAll(".dropdown-item"); Assert.Single(menus); - await cut.InvokeAsync(() => cut.Instance.TriggerOnChange("test")); - Assert.Equal("test", val); - Assert.Empty(cut.Instance.Value); - var button = cut.Find(".fa-magnifying-glass"); await cut.InvokeAsync(() => button.Click()); await Task.Delay(10); @@ -98,7 +115,7 @@ public async Task OnSearchClick_Ok() public async Task OnClearClick_Ok() { var ret = false; - var cut = Context.RenderComponent(builder => + var cut = Context.RenderComponent>(builder => { builder.Add(s => s.Value, "1"); builder.Add(s => s.ShowClearButton, true); From 563774d7c2652448e54a10bfbea7b20d530144f5 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:54:13 +0800 Subject: [PATCH 8/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 --- src/BootstrapBlazor.Server/Components/Samples/Searches.razor | 1 - src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor index 0616d940bfb..bf26b1f551d 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor @@ -39,7 +39,6 @@ Introduction="@Localizer["SearchesItemTemplateIntro"]" Name="ItemTemplate">
@context.Name
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs index 46667adb18b..6cd10797ebf 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs @@ -54,8 +54,6 @@ private Task> OnKeyboardSearch(string searchText) private Foo Model { get; set; } = new Foo() { Name = "" }; - private static string? GetDisplayText(Foo foo) => foo.Name; - private static async Task> OnSearchFoo(string searchText) { await Task.Delay(100); From af0222c3fb8e5dbafff8173a0f6ccf9cd41227af Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Mon, 30 Dec 2024 19:58:50 +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 --- test/UnitTest/Components/SearchTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/UnitTest/Components/SearchTest.cs b/test/UnitTest/Components/SearchTest.cs index 8edd15d0479..0857063dcbc 100644 --- a/test/UnitTest/Components/SearchTest.cs +++ b/test/UnitTest/Components/SearchTest.cs @@ -50,15 +50,15 @@ public async Task ItemTemplate_Ok() [Fact] public async Task OnGetDisplayText_Ok() { - var items = new List() { new() { Name = "test1", Address = "Address 1" }, new() { Name = "test2", Address = "Address 2" } }; - var cut = Context.RenderComponent>(pb => + var items = new List() { null, new() { Name = "test1", Address = "Address 1" }, new() { Name = "test2", Address = "Address 2" } }; + var cut = Context.RenderComponent>(pb => { pb.Add(a => a.OnSearch, async v => { await Task.Delay(1); return items; }); - pb.Add(a => a.OnGetDisplayText, foo => foo.Name); + pb.Add(a => a.OnGetDisplayText, foo => foo?.Name); }); await cut.InvokeAsync(() => cut.Instance.TriggerOnChange("t"));