Skip to content
18 changes: 9 additions & 9 deletions src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@
<section ignore>
<div>@((MarkupString)Localizer["TreeViewCheckboxTips1"].Value)</div>
<div>@((MarkupString)Localizer["TreeViewCheckboxTips2"].Value)</div>
</section>
<section ignore class="row form-inline">
<div class="col-12 col-lg-auto">
<Checkbox DisplayText="@Localizer["TreeViewCheckboxCheckBoxDisplayText1"]" ShowAfterLabel="true" @bind-Value="@AutoCheckChildren"></Checkbox>
<Checkbox DisplayText="@Localizer["TreeViewCheckboxCheckBoxDisplayText2"]" ShowAfterLabel="true" @bind-Value="@AutoCheckParent" class="ms-3"></Checkbox>
</div>
<div class="col-12 col-lg-auto">
<Button Text="@Localizer["TreeViewCheckboxButtonText"]" OnClick="@OnRefresh"></Button>
<Button Text="@Localizer["TreeViewCheckboxAddButtonText"]" OnClick="OnClickAddNode" class="ms-3"></Button>
<div class="row form-inline">
<div class="col-12 col-lg-auto">
<Checkbox DisplayText="@Localizer["TreeViewCheckboxCheckBoxDisplayText1"]" ShowAfterLabel="true" @bind-Value="@AutoCheckChildren"></Checkbox>
<Checkbox DisplayText="@Localizer["TreeViewCheckboxCheckBoxDisplayText2"]" ShowAfterLabel="true" @bind-Value="@AutoCheckParent" class="ms-3"></Checkbox>
</div>
<div class="col-12 col-lg-auto">
<Button Text="@Localizer["TreeViewCheckboxButtonText"]" OnClick="@OnRefresh"></Button>
<Button Text="@Localizer["TreeViewCheckboxAddButtonText"]" OnClick="OnClickAddNode" class="ms-3"></Button>
</div>
</div>
</section>
<TreeView Items="@CheckedItems" ShowCheckbox="true" OnTreeItemChecked="@OnTreeItemChecked" AutoCheckChildren="@AutoCheckChildren" AutoCheckParent="@AutoCheckParent"></TreeView>
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>9.3.1-beta11</Version>
<Version>9.3.1-beta16</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
14 changes: 12 additions & 2 deletions src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>

private string? EnableKeyboardString => EnableKeyboard ? "true" : null;

private bool _shouldRender = true;

private static string? GetItemTextClassString(TreeViewItem<TItem> item) => CssBuilder.Default("tree-node-text")
.AddClass(item.CssClass)
.Build();
Expand Down Expand Up @@ -355,13 +357,15 @@ protected override void OnParametersSet()
protected override async Task OnParametersSetAsync()
{
_rows = null;
TreeNodeStateCache.Reset();

if (Items != null)
{
if (Items.Count > 0)
{
_shouldRender = false;
await CheckExpand(Items);
_shouldRender = true;

_rows = null;
}

if (ShowCheckbox && (AutoCheckParent || AutoCheckChildren))
Expand Down Expand Up @@ -402,6 +406,12 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
}
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
protected override bool ShouldRender() => _shouldRender;

/// <summary>
/// <inheritdoc/>
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/Misc/ExpandableNodeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public async Task CheckExpandAsync(TNode node, Func<TNode, Task<IEnumerable<IExp
if (ExpandedNodeCache.Contains(node.Value))
{
// 原来是展开状态,
if (node.HasChildren)
if (node.HasChildren || node.Items.Any())
{
// 当前节点有子节点
node.IsExpand = true;
Expand Down
74 changes: 74 additions & 0 deletions test/UnitTest/Components/TreeViewTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,80 @@ public async Task OnExpandRowAsync_Ok()
Assert.True(expanded);
}

[Fact]
public async Task KeepExpandState_Ok()
{
// UI 重新刷新后保持状态节点状态
var items = TreeFoo.GetTreeItems();
items.RemoveAt(1);
items.RemoveAt(1);
items[0].HasChildren = true;

var cut = Context.RenderComponent<TreeView<TreeFoo>>(pb =>
{
pb.Add(a => a.Items, items);
pb.Add(a => a.OnExpandNodeAsync, item =>
{
return OnExpandNodeAsync(item.Value);
});
});
var nodes = cut.FindAll(".tree-node");
Assert.Single(nodes);

// 展开节点
var bar = cut.Find(".fa-caret-right.visible");
await cut.InvokeAsync(() => bar.Click());

cut.WaitForAssertion(() =>
{
nodes = cut.FindAll(".tree-node");
Assert.Equal(3, nodes.Count);
});

// 重新渲染
items = TreeFoo.GetTreeItems();
items.RemoveAt(1);
items.RemoveAt(1);
items[0].HasChildren = true;
cut.SetParametersAndRender(pb =>
{
pb.Add(a => a.Items, items);
});

cut.WaitForAssertion(() =>
{
nodes = cut.FindAll(".tree-node");
Assert.Equal(3, nodes.Count);
});

// 重新渲染
items = TreeFoo.GetTreeItems();
items.RemoveAt(1);
items.RemoveAt(1);
items[0].HasChildren = false;
items[0].Items =
[
new(new TreeFoo() { Id = "101", ParentId = "1010" })
{
Text = "懒加载子节点11",
HasChildren = true
},
new(new TreeFoo(){ Id = "102", ParentId = "1010" })
{
Text = "懒加载子节点22"
}
];
cut.SetParametersAndRender(pb =>
{
pb.Add(a => a.Items, items);
});
cut.WaitForAssertion(() =>
{
nodes = cut.FindAll(".tree-node");
Assert.Equal(3, nodes.Count);
});
}

[Fact]
public async Task OnExpandRowAsync_CheckCascadeState_Ok()
{
Expand Down