Skip to content

Commit a1e4a1a

Browse files
ArgoZhangyc-2503
andauthored
feat(TreeView): add SetItems instance method (#4934)
* chore: bump version 9.1.9-beta02 * refactor: 移除 IsReset 参数 Co-Authored-By: Chason <yuchen7701@foxmail.com> * refactor: SelectTree 组件移除 IsReset 参数 Co-Authored-By: Chason <yuchen7701@foxmail.com> * refactor: 更改私有属性为私有变量 Co-Authored-By: Chason <yuchen7701@foxmail.com> * Revert "refactor: SelectTree 组件移除 IsReset 参数" This reverts commit ac16979. * Revert "refactor: 移除 IsReset 参数" This reverts commit a5eed01. * chore: 移除宏定义 Co-Authored-By: Chason <yuchen7701@foxmail.com> * refactor: 增加 IsReset 支持 * feat: 增加 SetItems 方法 Co-Authored-By: Chason <yuchen7701@foxmail.com> * refactor: 临时移除 FlatItems * test: 增加单元测试 --------- Co-authored-by: Chason <yuchen7701@foxmail.com>
1 parent 3d2bbff commit a1e4a1a

File tree

3 files changed

+97
-29
lines changed

3 files changed

+97
-29
lines changed

src/BootstrapBlazor/BootstrapBlazor.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>9.1.9-beta01</Version>
4+
<Version>9.1.9-beta02</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs

+56-26
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ namespace BootstrapBlazor.Components;
1111
/// <summary>
1212
/// Tree 组件
1313
/// </summary>
14-
#if NET6_0_OR_GREATER
1514
[CascadingTypeParameter(nameof(TItem))]
16-
#endif
1715
public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
1816
{
1917
/// <summary>
@@ -58,7 +56,7 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
5856
.Build();
5957

6058
private string? GetContentClassString(TreeViewItem<TItem> item) => CssBuilder.Default("tree-content")
61-
.AddClass("active", ActiveItem == item)
59+
.AddClass("active", _activeItem == item)
6260
.Build();
6361

6462
private string? GetNodeClassString(TreeViewItem<TItem> item) => CssBuilder.Default("tree-node")
@@ -74,7 +72,7 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
7472
/// <summary>
7573
/// 获得/设置 选中节点 默认 null
7674
/// </summary>
77-
private TreeViewItem<TItem>? ActiveItem { get; set; }
75+
private TreeViewItem<TItem>? _activeItem;
7876

7977
/// <summary>
8078
/// 获得/设置 是否禁用整个组件 默认 false
@@ -168,11 +166,11 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
168166
[NotNull]
169167
public List<TreeViewItem<TItem>>? Items { get; set; }
170168

171-
/// <summary>
172-
/// 获得/设置 扁平化数据集合注意 <see cref="TreeViewItem{TItem}.Parent"/> 参数一定要赋值,不然无法呈现层次结构
173-
/// </summary>
174-
[Parameter]
175-
public List<TreeViewItem<TItem>>? FlatItems { get; set; }
169+
///// <summary>
170+
///// 获得/设置 扁平化数据集合注意 <see cref="TreeViewItem{TItem}.Parent"/> 参数一定要赋值,不然无法呈现层次结构
171+
///// </summary>
172+
//[Parameter]
173+
//public List<TreeViewItem<TItem>>? FlatItems { get; set; }
176174

177175
/// <summary>
178176
/// 获得/设置 是否显示 CheckBox 默认 false 不显示
@@ -347,6 +345,11 @@ protected override void OnParametersSet()
347345
SearchIcon ??= IconTheme.GetIconByKey(ComponentIcons.TreeViewSearchIcon);
348346
ClearSearchIcon ??= IconTheme.GetIconByKey(ComponentIcons.TreeViewResetSearchIcon);
349347
LoadingIcon ??= IconTheme.GetIconByKey(ComponentIcons.TreeViewLoadingIcon);
348+
349+
if (IsReset)
350+
{
351+
_rows = null;
352+
}
350353
}
351354

352355
/// <summary>
@@ -355,8 +358,12 @@ protected override void OnParametersSet()
355358
/// <returns></returns>
356359
protected override async Task OnParametersSetAsync()
357360
{
358-
_rows = null;
359-
Items ??= [];
361+
if (Items == null)
362+
{
363+
// 未提供数据显示 loading
364+
return;
365+
}
366+
360367
if (Items.Count > 0)
361368
{
362369
await CheckExpand(Items);
@@ -369,16 +376,16 @@ protected override async Task OnParametersSetAsync()
369376
}
370377

371378
// 从数据源中恢复当前 active 节点
372-
if (ActiveItem != null)
379+
if (_activeItem != null)
373380
{
374-
ActiveItem = TreeNodeStateCache.Find(Items, ActiveItem.Value, out _);
381+
_activeItem = TreeNodeStateCache.Find(Items, _activeItem.Value, out _);
375382
}
376383

377384
if (_init == false)
378385
{
379386
// 设置 ActiveItem 默认值
380-
ActiveItem ??= Items.FirstOrDefaultActiveItem();
381-
ActiveItem?.SetParentExpand<TreeViewItem<TItem>, TItem>(true);
387+
_activeItem ??= Items.FirstOrDefaultActiveItem();
388+
_activeItem?.SetParentExpand<TreeViewItem<TItem>, TItem>(true);
382389
_init = true;
383390
}
384391
}
@@ -417,16 +424,16 @@ public async ValueTask TriggerKeyDown(string key)
417424
{
418425
// 通过 ActiveItem 找到兄弟节点
419426
// 如果兄弟节点没有时,找到父亲节点
420-
if (ActiveItem != null)
427+
if (_activeItem != null)
421428
{
422429
if (key == "ArrowUp" || key == "ArrowDown")
423430
{
424431
_keyboardArrowUpDownTrigger = true;
425-
await ActiveTreeViewItem(key, ActiveItem);
432+
await ActiveTreeViewItem(key, _activeItem);
426433
}
427434
else if (key == "ArrowLeft" || key == "ArrowRight")
428435
{
429-
await OnToggleNodeAsync(ActiveItem, true);
436+
await OnToggleNodeAsync(_activeItem, true);
430437
}
431438
}
432439
}
@@ -574,7 +581,7 @@ private async Task<IEnumerable<IExpandableNode<TItem>>> GetChildrenRowAsync(Tree
574581
/// <returns></returns>
575582
private async Task OnClick(TreeViewItem<TItem> item)
576583
{
577-
ActiveItem = item;
584+
_activeItem = item;
578585
if (ClickToggleNode && CanTriggerClickNode(item))
579586
{
580587
await OnToggleNodeAsync(item);
@@ -622,21 +629,43 @@ private async Task OnClickResetSearch()
622629
/// <summary>
623630
/// 设置选中节点
624631
/// </summary>
625-
public void SetActiveItem(TreeViewItem<TItem> item)
632+
public void SetActiveItem(TreeViewItem<TItem>? item)
633+
{
634+
_activeItem = item;
635+
_activeItem?.SetParentExpand<TreeViewItem<TItem>, TItem>(true);
636+
StateHasChanged();
637+
}
638+
639+
/// <summary>
640+
/// 重新设置 <see cref="Items"/> 数据源方法
641+
/// </summary>
642+
public void SetItems(List<TreeViewItem<TItem>> items)
626643
{
627-
ActiveItem = item;
628-
ActiveItem.SetParentExpand<TreeViewItem<TItem>, TItem>(true);
644+
//FlatItems = null;
645+
Items = items;
646+
_rows = null;
629647
StateHasChanged();
630648
}
631649

650+
///// <summary>
651+
///// 重新设置 <see cref="FlatItems"/> 数据源方法
652+
///// </summary>
653+
///// <param name="flatItems"></param>
654+
//public void SetFlatItems(List<TreeViewItem<TItem>> flatItems)
655+
//{
656+
// Items = null;
657+
// FlatItems = flatItems;
658+
// _rows = null;
659+
// StateHasChanged();
660+
//}
661+
632662
/// <summary>
633663
/// 设置选中节点
634664
/// </summary>
635665
public void SetActiveItem(TItem item)
636666
{
637-
ActiveItem = Items.GetAllItems().FirstOrDefault(i => Equals(i.Value, item));
638-
ActiveItem?.SetParentExpand<TreeViewItem<TItem>, TItem>(true);
639-
StateHasChanged();
667+
var val = Items.GetAllItems().FirstOrDefault(i => Equals(i.Value, item));
668+
SetActiveItem(val);
640669
}
641670

642671
private static CheckboxState ToggleCheckState(CheckboxState state) => state switch
@@ -832,7 +861,8 @@ private List<TreeViewItem<TItem>> Rows
832861
{
833862
get
834863
{
835-
_rows ??= FlatItems ?? Items.ToFlat<TItem>().ToList();
864+
// 扁平化数据集合
865+
_rows ??= Items.ToFlat<TItem>().ToList();
836866
return _rows;
837867
}
838868
}

test/UnitTest/Components/TreeViewTest.cs

+40-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace UnitTest.Components;
88
public class TreeViewTest : BootstrapBlazorTestBase
99
{
1010
[Fact]
11-
public void Items_Ok()
11+
public async Task Items_Ok()
1212
{
1313
var cut = Context.RenderComponent<TreeView<TreeFoo>>();
1414
cut.DoesNotContain("tree-root");
@@ -25,16 +25,54 @@ public void Items_Ok()
2525
{
2626
pb.Add(a => a.Items, TreeFoo.GetTreeItems());
2727
});
28-
cut.Contains("li");
28+
var items = cut.FindAll(".tree-content");
29+
Assert.Equal(9, items.Count);
2930

3031
cut.SetParametersAndRender(pb =>
3132
{
3233
pb.Add(a => a.Items, null);
3334
pb.Add(a => a.ShowSkeleton, false);
3435
});
3536
Assert.Equal("", cut.Markup);
37+
38+
// SetItems
39+
await cut.InvokeAsync(() => cut.Instance.SetItems(
40+
[
41+
new TreeViewItem<TreeFoo>(new TreeFoo() { Text = "Test1" }) { Text = "Test1" },
42+
new TreeViewItem<TreeFoo>(new TreeFoo() { Text = "Test2" }) { Text = "Test2" }
43+
]));
44+
45+
items = cut.FindAll(".tree-content");
46+
Assert.Equal(2, items.Count);
3647
}
3748

49+
//[Fact]
50+
//public void FlatItems_Ok()
51+
//{
52+
// var cut = Context.RenderComponent<TreeView<TreeFoo>>(pb =>
53+
// {
54+
// pb.Add(a => a.FlatItems, TreeFoo.GetFlatItems());
55+
// });
56+
// cut.WaitForElement(".tree-view");
57+
58+
// // 验证树形结构正确生成
59+
// var nodes = cut.FindAll(".tree-content");
60+
// Assert.Equal(3, nodes.Count);
61+
62+
// // 验证父子关系
63+
// var parentNode = cut.Find("[data-item-id='1']");
64+
// Assert.NotNull(parentNode);
65+
// var childNode = cut.Find("[data-item-id='2']");
66+
// Assert.NotNull(childNode);
67+
// Assert.Contains("tree-children", childNode.ParentElement?.ClassName);
68+
69+
// cut.SetParametersAndRender(pb =>
70+
// {
71+
// pb.Add(a => a.FlatItems, null);
72+
// });
73+
// Assert.Equal("", cut.Markup);
74+
//}
75+
3876
[Fact]
3977
public void Items_Disabled()
4078
{

0 commit comments

Comments
 (0)