From 7845da5d8017a26204e8e1989766b3387fe0045a Mon Sep 17 00:00:00 2001 From: zglp <2499728776@qq.com> Date: Sun, 21 Mar 2021 14:05:22 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8DTable=E6=A0=91=E5=BD=A2?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E6=95=B0=E6=8D=AE=E6=BA=90=E4=B8=8D=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs index 81b69300b..741be7b42 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs @@ -295,6 +295,13 @@ namespace BootstrapBlazor.Components if (queryData != null) { Items = queryData.Items; + if (IsTree) + { + TreeRows = Items.Select(item => new TableTreeNode(item) + { + HasChildren = CheckTreeChildren(item) + }).ToList(); + } TotalCount = queryData.TotalCount; IsFiltered = queryData.IsFiltered; IsSorted = queryData.IsSorted; -- Gitee From 8121e7b1e9c0770c8b2931181c71de365c75cc96 Mon Sep 17 00:00:00 2001 From: zglp <2499728776@qq.com> Date: Sun, 21 Mar 2021 14:05:56 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=85=B7=E6=9C=89?= =?UTF-8?q?=E5=8D=95=E8=A1=A8=E7=BB=B4=E6=8A=A4=E5=8A=9F=E8=83=BD=E7=9A=84?= =?UTF-8?q?=E6=A0=91=E5=BD=A2=E6=95=B0=E6=8D=AE=E6=A1=88=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pages/Samples/Table/TablesTree.razor | 16 ++++ .../Pages/Samples/Table/TablesTree.razor.cs | 80 +++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor b/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor index 22532934a..33aed83af 100644 --- a/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor +++ b/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor @@ -35,3 +35,19 @@ + + + + + + + + + + + +
+
diff --git a/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor.cs b/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor.cs index 6378dc49a..72b03e79f 100644 --- a/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor.cs +++ b/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Website: https://www.blazor.zone or https://argozhang.github.io/ +using BootstrapBlazor.Components; using BootstrapBlazor.Shared.Pages.Components; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; @@ -18,6 +19,9 @@ namespace BootstrapBlazor.Shared.Pages.Table /// public partial class TablesTree { + [NotNull] + private List? AllItems { get; set; } + [NotNull] private IEnumerable? TreeItems { get; set; } @@ -35,6 +39,14 @@ namespace BootstrapBlazor.Shared.Pages.Table base.OnInitialized(); TreeItems = FooTree.Generate(Localizer); + AllItems = new List(); + AllItems.AddRange(EditFooTree.Generate(Localizer, AllItems)); + AllItems.AddRange(EditFooTree.Generate(Localizer, AllItems, 10, 1)); + AllItems.AddRange(EditFooTree.Generate(Localizer, AllItems, 20, 2)); + AllItems.AddRange(EditFooTree.Generate(Localizer, AllItems, 30, 11)); + AllItems.AddRange(EditFooTree.Generate(Localizer, AllItems, 40, 12)); + AllItems.AddRange(EditFooTree.Generate(Localizer, AllItems, 50, 21)); + AllItems.AddRange(EditFooTree.Generate(Localizer, AllItems, 60, 22)); } private async Task> OnTreeExpand(FooTree foo) @@ -47,6 +59,49 @@ namespace BootstrapBlazor.Shared.Pages.Table }); } + private Task OnAddAsync() => Task.FromResult(new EditFooTree() { AllItems = AllItems, DateTime = DateTime.Now }); + + private Task OnSaveAsync(EditFooTree item) + { + if (item.Id == 0) + { + item.Id = AllItems.Max(i => i.Id) + 1; + AllItems.Add(item); + } + else + { + var oldItem = AllItems.FirstOrDefault(i => i.Id == item.Id); + if (oldItem != null) + { + oldItem.ParentId = item.ParentId; + oldItem.Name = item.Name; + oldItem.DateTime = item.DateTime; + oldItem.Address = item.Address; + oldItem.Count = item.Count; + } + } + return Task.FromResult(true); + } + + private Task OnDeleteAsync(IEnumerable items) + { + items.ToList().ForEach(i => AllItems.Remove(i)); + return Task.FromResult(true); + } + + private Task> OnQueryAsync(QueryPageOptions _) + { + return Task.FromResult(new QueryData() + { + Items = AllItems.Where(f => f.ParentId == 0) + }); + } + + private Task> OnTreeExpandQuary(EditFooTree foo) + { + return Task.FromResult(AllItems.Where(f => f.ParentId == foo.Id)); + } + private class FooTree : Foo { private static readonly Random random = new(); @@ -67,5 +122,30 @@ namespace BootstrapBlazor.Shared.Pages.Table HasChildren = hasChildren }).ToList(); } + + private class EditFooTree : Foo + { + private static readonly Random random = new(); + + [NotNull] + public List? AllItems { get; set; } + + public int ParentId { get; set; } + + public IEnumerable? Children { get; set; } + + public bool HasChildren => AllItems.Any(i => i.ParentId == Id); + + public static IEnumerable Generate(IStringLocalizer localizer, List list, int seed = 0, int parentId = 0) => Enumerable.Range(1, 2).Select(i => new EditFooTree() + { + Id = i + seed, + ParentId = parentId, + Name = localizer["Foo.Name", $"{seed:d2}{(i + seed):d2}"], + DateTime = System.DateTime.Now.AddDays(i - 1), + Address = localizer["Foo.Address", $"{random.Next(1000, 2000)}"], + Count = random.Next(1, 100), + AllItems = list + }).ToList(); + } } } -- Gitee From 8f69895be30f53304c59d695ad3429567b0ae5bf Mon Sep 17 00:00:00 2001 From: zglp <2499728776@qq.com> Date: Sun, 21 Mar 2021 19:29:48 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=90=8ETable=E6=A0=91=E5=BD=A2=E7=BB=93=E6=9E=84=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=94=B6=E7=BC=A9=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pages/Components/Foo.cs | 1 + .../Pages/Samples/Table/TablesTree.razor | 7 +- .../Components/Table/Table.razor.Edit.cs | 70 +++++++++++++++++-- .../Components/Table/TableTreeNode.cs | 29 ++++++++ 4 files changed, 101 insertions(+), 6 deletions(-) diff --git a/src/BootstrapBlazor.Shared/Pages/Components/Foo.cs b/src/BootstrapBlazor.Shared/Pages/Components/Foo.cs index edc4e70f4..4b780be63 100644 --- a/src/BootstrapBlazor.Shared/Pages/Components/Foo.cs +++ b/src/BootstrapBlazor.Shared/Pages/Components/Foo.cs @@ -21,6 +21,7 @@ namespace BootstrapBlazor.Shared.Pages.Components /// /// /// + [Key] [Display(Name = "主键")] [AutoGenerateColumn(Ignore = true)] public int Id { get; set; } diff --git a/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor b/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor index 33aed83af..91f32494b 100644 --- a/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor +++ b/src/BootstrapBlazor.Shared/Pages/Samples/Table/TablesTree.razor @@ -37,10 +37,13 @@ - +
通过在实体的唯一标识字段上定义 [Key] 特性,来保持展开状态
+ +
+ OnDeleteAsync="@OnDeleteAsync" OnTreeExpand="@OnTreeExpandQuary"> diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs index 741be7b42..e6791cca6 100644 --- a/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs +++ b/src/BootstrapBlazor/Components/Table/Table.razor.Edit.cs @@ -297,10 +297,34 @@ namespace BootstrapBlazor.Components Items = queryData.Items; if (IsTree) { - TreeRows = Items.Select(item => new TableTreeNode(item) + KeySet.Clear(); + if (TableTreeNode.HasKey) { - HasChildren = CheckTreeChildren(item) - }).ToList(); + CheckExpandKeys(TreeRows); + } + if (KeySet.Count > 0) + { + TreeRows = Items.Select(item => + { + var node = new TableTreeNode(item) + { + HasChildren = CheckTreeChildren(item), + }; + node.IsExpand = node.HasChildren && node.Key != null && KeySet.Contains(node.Key); + if (node.IsExpand) + { + RestoreIsExpand(node); + } + return node; + }).ToList(); + } + else + { + TreeRows = Items.Select(item => new TableTreeNode(item) + { + HasChildren = CheckTreeChildren(item) + }).ToList(); + } } TotalCount = queryData.TotalCount; IsFiltered = queryData.IsFiltered; @@ -328,6 +352,44 @@ namespace BootstrapBlazor.Components } } + private HashSet KeySet { get; } = new(); + + private void CheckExpandKeys(List> tableTreeNodes) + { + foreach (var node in tableTreeNodes) + { + if (node.IsExpand && node.Key != null) + { + KeySet.Add(node.Key); + } + CheckExpandKeys(node.Children); + } + } + + private void RestoreIsExpand(TableTreeNode parentNode) + { + if (OnTreeExpand == null) + { + throw new InvalidOperationException(NotSetOnTreeExpandErrorMessage); + } + + var items = OnTreeExpand(parentNode.Value).Result; + parentNode.Children.AddRange(items.Select(item => + { + var node = new TableTreeNode(item) + { + HasChildren = CheckTreeChildren(item), + Parent = parentNode + }; + node.IsExpand = node.HasChildren && node.Key != null && KeySet.Contains(node.Key); + if (node.IsExpand) + { + RestoreIsExpand(node); + } + return node; + })); + } + private static readonly ConcurrentDictionary, string, SortOrder, IEnumerable>> SortLambdaCache = new(); private async Task ClickEditButton(TItem item) @@ -373,4 +435,4 @@ namespace BootstrapBlazor.Components return Task.FromResult(true); }; } -} +} \ No newline at end of file diff --git a/src/BootstrapBlazor/Components/Table/TableTreeNode.cs b/src/BootstrapBlazor/Components/Table/TableTreeNode.cs index 23548cdcf..76a616983 100644 --- a/src/BootstrapBlazor/Components/Table/TableTreeNode.cs +++ b/src/BootstrapBlazor/Components/Table/TableTreeNode.cs @@ -2,7 +2,12 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Website: https://www.blazor.zone or https://argozhang.github.io/ +using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; namespace BootstrapBlazor.Components { @@ -12,11 +17,34 @@ namespace BootstrapBlazor.Components /// public class TableTreeNode where TItem : class { + private static readonly Lazy> GetKeyFunc = new(() => + { + var property = typeof(TItem).GetProperties().FirstOrDefault(p => p.IsDefined(typeof(KeyAttribute))); + if (property == null) + { + return _ => null; + } + HasKey = true; + var param = Expression.Parameter(typeof(TItem)); + var body = Expression.Property(param, property); + return Expression.Lambda>(Expression.Convert(body, typeof(object)), param).Compile(); + }); + + /// + /// 获取 TItem 是否存在唯一标识 + /// + public static bool HasKey { get; private set; } + /// /// 获得/设置 当前节点值 /// public TItem Value { get; } + /// + /// 获得/设置 当前节点唯一标识 + /// + public object? Key { get; } + /// /// 获得/设置 是否展开 /// @@ -43,6 +71,7 @@ namespace BootstrapBlazor.Components public TableTreeNode(TItem item) { Value = item; + Key = GetKeyFunc.Value(item); } } } -- Gitee