Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(TreeView): redesign TreeNode state cache #4953

Merged
merged 24 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 20 additions & 45 deletions src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
Introduction="@Localizer["TreeViewNormalIntro"]"
Name="Normal">
<section ignore>@((MarkupString)Localizer["TreeViewNormalDescription"].Value)</section>
<TreeView TItem="TreeFoo" Items="@Items" OnTreeItemClick="@OnTreeItemClick" />
<TreeView Items="@NormalItems" OnTreeItemClick="@OnTreeItemClick" />
<ConsoleLogger @ref="Logger1" />
</DemoBlock>

Expand All @@ -45,9 +45,10 @@
</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>
</section>
<TreeView TItem="TreeFoo" Items="@CheckedItems" ShowCheckbox="true" OnTreeItemChecked="@OnTreeItemChecked" AutoCheckChildren="@AutoCheckChildren" AutoCheckParent="@AutoCheckParent"></TreeView>
<TreeView Items="@CheckedItems" ShowCheckbox="true" OnTreeItemChecked="@OnTreeItemChecked" AutoCheckChildren="@AutoCheckChildren" AutoCheckParent="@AutoCheckParent"></TreeView>
<ConsoleLogger @ref="Logger2"></ConsoleLogger>
</DemoBlock>

Expand All @@ -59,14 +60,14 @@
<Checkbox DisplayText="@Localizer["TreeViewsDisableWholeTreeView"]" ShowAfterLabel="true" @bind-Value="@IsDisabled"></Checkbox>
<Checkbox DisplayText="@Localizer["TreeViewsWhetherToExpandWhenDisable"]" ShowAfterLabel="true" @bind-Value="@DisableCanExpand" class="ms-3"></Checkbox>
</div>
<TreeView TItem="TreeFoo" Items="@DisabledItems" ShowCheckbox="true" IsDisabled="@IsDisabled" CanExpandWhenDisabled="@DisableCanExpand"></TreeView>
<TreeView Items="@DisabledItems" ShowCheckbox="true" IsDisabled="@IsDisabled" CanExpandWhenDisabled="@DisableCanExpand"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewAccordionModelTitle"]"
Introduction="@Localizer["TreeViewAccordionModelIntro"]"
Name="AccordionModel">
<section ignore>@((MarkupString)Localizer["TreeViewAccordionModelDescription"].Value)</section>
<TreeView TItem="TreeFoo" Items="@GetAccordionItems()" OnExpandNodeAsync="OnExpandNodeAsync" ShowCheckbox="true" IsAccordion="true"></TreeView>
<TreeView Items="@AccordionItems" OnExpandNodeAsync="TreeFoo.OnExpandAccordionNodeAsync" ShowCheckbox="true" IsAccordion="true"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewDefaultExpandTitle"]"
Expand All @@ -75,7 +76,7 @@
<section ignore>
@((MarkupString)Localizer["TreeViewDefaultExpandDescription"].Value)
</section>
<TreeView TItem="TreeFoo" Items="@ExpandItems" ShowCheckbox="true"></TreeView>
<TreeView Items="@ExpandItems" ShowCheckbox="true"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewTreeDisplayIconTitle"]"
Expand All @@ -84,7 +85,7 @@
<section ignore>
@((MarkupString)Localizer["TreeViewTreeDisplayIconDescription"].Value)
</section>
<TreeView TItem="TreeFoo" Items="@GetIconItems()" ShowIcon="true" ShowCheckbox="true"></TreeView>
<TreeView Items="@IconItems" ShowIcon="true" ShowCheckbox="true"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewTreeClickExpandTitle"]"
Expand All @@ -93,15 +94,15 @@
<section ignore>
@((MarkupString)Localizer["TreeViewTreeClickExpandDescription"].Value)
</section>
<TreeView TItem="TreeFoo" Items="@GetClickExpandItems" ShowIcon="true" ShowCheckbox="true" ClickToggleNode="true"></TreeView>
<TreeView Items="@ClickExpandItems" ShowIcon="true" ShowCheckbox="true" ClickToggleNode="true"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewTreeValidationFormTitle"]"
Introduction="@Localizer["TreeViewTreeValidationFormIntro"]"
Name="TreeValidationForm">
<section ignore>@((MarkupString)Localizer["TreeViewTreeValidationFormDescription"].Value)</section>
<ValidateForm Model="@Model">
<TreeView TItem="TreeFoo" Items="@GetFormItems" OnTreeItemClick="@OnFormTreeItemClick" ShowCheckbox="true"></TreeView>
<TreeView Items="@FormItems" OnTreeItemClick="@OnFormTreeItemClick" ShowCheckbox="true"></TreeView>
</ValidateForm>
</DemoBlock>

Expand All @@ -111,44 +112,28 @@
<section ignore>
@((MarkupString)Localizer["TreeViewTreeLazyLoadingDescription"].Value)
</section>
<TreeView TItem="TreeFoo" ClickToggleNode="true" Items="@GetLazyItems()" OnExpandNodeAsync="OnExpandNodeAsync"></TreeView>
<TreeView ClickToggleNode="true" Items="@LazyItems" OnExpandNodeAsync="TreeFoo.OnExpandAccordionNodeAsync"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewTreeCustomNodeTitle"]"
Introduction="@Localizer["TreeViewTreeCustomNodeIntro"]"
Name="TreeCustomNode">
<TreeView TItem="TreeFoo" ClickToggleNode="true" Items="GetTemplateItems()"></TreeView>
<TreeView ClickToggleNode="true" Items="TemplateItems"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewTreeNodeColorTitle"]"
Introduction="@Localizer["TreeViewTreeNodeColorIntro"]"
Name="TreeNodeColor">
<TreeView TItem="TreeFoo" ClickToggleNode="true" Items="GetColorItems()"></TreeView>
<TreeView ClickToggleNode="true" Items="ColorItems"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewCheckedItemsTitle"]"
Introduction="@Localizer["TreeViewCheckedItemsIntro"]"
Name="CheckedItems">
<TreeView TItem="TreeFoo" ShowCheckbox="true" Items="@CheckedItems2" OnTreeItemChecked="@OnTreeItemChecked2"></TreeView>
<TreeView ShowCheckbox="true" Items="@CheckedItems2" OnTreeItemChecked="@OnTreeItemChecked2"></TreeView>
<ConsoleLogger @ref="Logger3"></ConsoleLogger>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewCustomCheckedItemsTitle"]"
Introduction="@Localizer["TreeViewCustomCheckedItemsIntro"]"
Name="CustomCheckedItems">
<section ignore>
<div>@((MarkupString)Localizer["TreeViewCustomCheckedItemsTips1"].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>
</section>
<TreeView TItem="TreeFoo" ShowCheckbox="true" ClickToggleNode="true" ClickToggleCheck="false" AutoCheckChildren="@AutoCheckChildren" AutoCheckParent="@AutoCheckParent"
Items="@GetCustomCheckedItems()" OnExpandNodeAsync="CustomCheckedNodeOnExpandNodeAsync"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewSetActiveTitle"]"
Introduction="@Localizer["TreeViewSetActiveIntro"]"
Name="SetActive">
Expand All @@ -157,41 +142,41 @@
<Select TValue="string" Items="SelectedItems" OnSelectedItemChanged="SelectedItemOnChanged" ShowLabel="true" DisplayText="@Localizer["TreeViewSetActiveDisplayText"]"></Select>
</div>
</section>
<TreeView @ref="SetActiveTreeView" TItem="TreeFoo" Items="@Items" OnTreeItemClick="@OnTreeItemClick"></TreeView>
<TreeView @ref="SetActiveTreeView" Items="@Items" OnTreeItemClick="@OnTreeItemClick"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewShowSkeletonTitle"]"
Introduction="@Localizer["TreeViewShowSkeletonIntro"]"
Name="ShowSkeleton">
<Button Text="@Localizer["TreeViewShowSkeletonButtonText"]" IsAsync="true" Icon="fa-solid fa-font-awesome" OnClick="@OnLoadAsyncItems"></Button>
<TreeView TItem="TreeFoo" Items="@AsyncItems" ShowSkeleton="true" OnExpandNodeAsync="OnExpandNodeAsync" class="mt-3"></TreeView>
<TreeView Items="@AsyncItems" ShowSkeleton="true" OnExpandNodeAsync="OnExpandNodeAsync" class="mt-3"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewShowSearchTitle"]"
Introduction="@Localizer["TreeViewShowSearchIntro"]"
Name="ShowSearch">
<TreeView TItem="TreeFoo" Items="@SearchItems1" ShowSearch="true" OnSearchAsync="@OnSearchAsync"></TreeView>
<TreeView Items="@SearchItems1" ShowSearch="true" OnSearchAsync="@OnSearchAsync"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewFixedSearchTitle"]"
Introduction="@Localizer["TreeViewFixedSearchIntro"]"
Name="IsFixedSearch">
<TreeView TItem="TreeFoo" Items="@SearchItems2" ShowSearch="true" OnSearchAsync="@OnSearchAsync" IsFixedSearch="true" style="height: 180px;"></TreeView>
<TreeView Items="@SearchItems2" ShowSearch="true" OnSearchAsync="@OnSearchAsync" IsFixedSearch="true" style="height: 180px;"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewMaxSelectedCountTitle"]"
Introduction="@Localizer["TreeViewMaxSelectedCountIntro"]"
Name="MaxSelectedCount">
<section ignore>@((MarkupString)Localizer["TreeViewMaxSelectedCountDesc"].Value)</section>
<TreeView TItem="TreeFoo" Items="@MaxItems" ShowCheckbox="true" AutoCheckChildren="true" AutoCheckParent="true"
<TreeView Items="@MaxItems" ShowCheckbox="true" AutoCheckChildren="true" AutoCheckParent="true"
MaxSelectedCount="2" OnMaxSelectedCountExceed="OnMaxSelectedCountExceed"></TreeView>
</DemoBlock>

<DemoBlock Title="@Localizer["TreeViewEnableKeyboardArrowUpDownTitle"]"
Introduction="@Localizer["TreeViewEnableKeyboardArrowUpDownIntro"]"
Name="EnableKeyboard">
<section ignore>@_selectedValue</section>
<TreeView TItem="TreeFoo" Items="@KeyboardItems" OnTreeItemClick="@OnTreeItemKeyboardClick" style="height: 160px;"
<TreeView Items="@KeyboardItems" OnTreeItemClick="@OnTreeItemKeyboardClick" style="height: 160px;"
EnableKeyboard="true" ClickToggleNode="false" ClickToggleCheck="false" ShowCheckbox="true" />
</DemoBlock>

Expand All @@ -202,22 +187,12 @@
@((MarkupString)Localizer["TreeViewVirtualizeDescription"].Value)
</section>
<div style="height: 400px">
<TreeView TItem="TreeFoo" Items="@VirtualizeItems" ShowCheckbox="true" IsVirtualize="true"
<TreeView Items="@VirtualizeItems" ShowCheckbox="true" IsVirtualize="true"
AutoCheckChildren="true" AutoCheckParent="true"
OnExpandNodeAsync="OnExpandVirtualNodeAsync"></TreeView>
</div>
</DemoBlock>

@* <DemoBlock Title="@Localizer["TreeViewFlatTitle"]"
Introduction="@Localizer["TreeViewFlatIntro"]"
Name="FlatItems">
<section ignore>
@((MarkupString)Localizer["TreeViewFlatItemsDescription"].Value)
</section>
<TreeView TItem="TreeFoo" Items="@FlatItems" ShowCheckbox="true"
AutoCheckChildren="true" AutoCheckParent="true"></TreeView>
</DemoBlock>
*@
<AttributeTable Items="@GetAttributes()"></AttributeTable>

<AttributeTable Items="@GetTreeItemAttributes()" Title="@Localizer["TreeViewsAttribute"]"></AttributeTable>
103 changes: 19 additions & 84 deletions src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ public sealed partial class TreeViews
private ConsoleLogger? Logger3 { get; set; }

private bool DisableCanExpand { get; set; }

private bool IsDisabled { get; set; }

private List<TreeViewItem<TreeFoo>> NormalItems { get; } = TreeFoo.GetTreeItems();

private List<TreeViewItem<TreeFoo>> Items { get; } = TreeFoo.GetTreeItems();

private bool AutoCheckChildren { get; set; }
Expand All @@ -33,15 +36,17 @@ public sealed partial class TreeViews

private List<TreeViewItem<TreeFoo>> DisabledItems { get; } = GetDisabledItems();

private List<TreeViewItem<TreeFoo>>? AccordionItems { get; } = TreeFoo.GetAccordionItems();

private List<TreeViewItem<TreeFoo>> ExpandItems { get; } = GetExpandItems();

private List<TreeViewItem<TreeFoo>> CheckedItems { get; set; } = GetCheckedItems();

private static List<TreeViewItem<TreeFoo>> GetIconItems() => TreeFoo.GetTreeItems();
private static List<TreeViewItem<TreeFoo>> IconItems { get; set; } = TreeFoo.GetTreeItems();

private List<TreeViewItem<TreeFoo>> GetClickExpandItems { get; } = TreeFoo.GetTreeItems();
private List<TreeViewItem<TreeFoo>> ClickExpandItems { get; } = TreeFoo.GetTreeItems();

private List<TreeViewItem<TreeFoo>> GetFormItems { get; } = TreeFoo.GetTreeItems();
private List<TreeViewItem<TreeFoo>> FormItems { get; } = TreeFoo.GetTreeItems();

private List<TreeViewItem<TreeFoo>> CheckedItems2 { get; } = TreeFoo.GetTreeItems();

Expand All @@ -61,7 +66,11 @@ public sealed partial class TreeViews

private List<TreeViewItem<TreeFoo>> VirtualizeItems { get; } = TreeFoo.GetVirtualizeTreeItems();

private List<TreeViewItem<TreeFoo>> FlatItems { get; } = TreeFoo.GetFlatItems();
private List<TreeViewItem<TreeFoo>> LazyItems { get; } = TreeFoo.GetLazyItems();

private List<TreeViewItem<TreeFoo>> ColorItems { get; } = TreeFoo.GetColorItems();

private List<TreeViewItem<TreeFoo>> TemplateItems { get; } = TreeFoo.GetTemplateItems();

private Foo Model => Foo.Generate(LocalizerFoo);

Expand All @@ -85,6 +94,11 @@ private void OnRefresh()
CheckedItems = GetCheckedItems();
}

private void OnClickAddNode()
{
CheckedItems.Add(new TreeViewItem<TreeFoo>(new TreeFoo() { Id = $"Id-{DateTime.Now.Ticks}" }) { Text = DateTime.Now.ToString() });
}

private static List<TreeViewItem<TreeFoo>> GetCheckedItems()
{
var ret = TreeFoo.GetTreeItems();
Expand Down Expand Up @@ -114,35 +128,13 @@ private static List<TreeViewItem<TreeFoo>> GetDisabledItems()
return ret;
}

private static List<TreeViewItem<TreeFoo>> GetAccordionItems()
{
var ret = TreeFoo.GetTreeItems();
ret[1].Items[0].HasChildren = true;
return ret;
}

private static async Task<IEnumerable<TreeViewItem<TreeFoo>>> OnExpandNodeAsync(TreeViewItem<TreeFoo> node)
{
await Task.Delay(800);
await Task.Delay(200);
var item = node.Value;
return new TreeViewItem<TreeFoo>[] { new(new TreeFoo() { Id = $"{item.Id}-101", ParentId = item.Id }) { Text = "懒加载子节点1", HasChildren = true }, new(new TreeFoo() { Id = $"{item.Id}-102", ParentId = item.Id }) { Text = "懒加载子节点2" } };
}

private static async Task<IEnumerable<TreeViewItem<TreeFoo>>> CustomCheckedNodeOnExpandNodeAsync(TreeViewItem<TreeFoo> node)
{
await Task.Delay(800);
var item = node.Value;
return TreeFoo.GetCheckedTreeItems(item.Id);
}

private static List<TreeViewItem<TreeFoo>> GetCustomCheckedItems()
{
var ret = TreeFoo.GetCheckedTreeItems();
ret[0].IsExpand = true;
ret[0].Items = TreeFoo.GetCheckedTreeItems();
return ret;
}

private static List<TreeViewItem<TreeFoo>> GetExpandItems()
{
var ret = TreeFoo.GetTreeItems();
Expand All @@ -155,31 +147,6 @@ private static Task OnFormTreeItemClick(TreeViewItem<TreeFoo> item)
return Task.CompletedTask;
}

private static List<TreeViewItem<TreeFoo>> GetLazyItems()
{
var ret = TreeFoo.GetTreeItems();
ret[1].Items[0].IsExpand = true;
ret[2].Text = "懒加载延时";
ret[2].HasChildren = true;
return ret;
}

private static List<TreeViewItem<TreeFoo>> GetTemplateItems()
{
var ret = TreeFoo.GetTreeItems();
ret[0].Template = foo => BootstrapDynamicComponent.CreateComponent<CustomerTreeItem>(new Dictionary<string, object?>() { [nameof(CustomerTreeItem.Foo)] = foo }).Render();
return ret;
}

private static List<TreeViewItem<TreeFoo>> GetColorItems()
{
var ret = TreeFoo.GetTreeItems();
ret[0].CssClass = "text-primary";
ret[1].CssClass = "text-success";
ret[2].CssClass = "text-danger";
return ret;
}

private Task OnTreeItemChecked2(List<TreeViewItem<TreeFoo>> items)
{
Logger3.Log($"当前共选中{items.Count}项");
Expand Down Expand Up @@ -249,38 +216,6 @@ private static async Task<IEnumerable<TreeViewItem<TreeFoo>>> OnExpandVirtualNod
return items;
}

private class CustomerTreeItem : ComponentBase
{
[Inject]
[NotNull]
private ToastService? ToastService { get; set; }

[Parameter]
[NotNull]
public TreeFoo? Foo { get; set; }

/// <summary>
/// BuildRenderTree
/// </summary>
/// <param name="builder"></param>
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(3, "span");
builder.AddAttribute(4, "class", "me-3");
builder.AddContent(5, Foo.Text);
builder.CloseElement();

builder.OpenComponent<Button>(0);
builder.AddAttribute(1, nameof(Button.Icon), "fa-solid fa-font-awesome");
builder.AddAttribute(2, nameof(Button.Text), "Click");
builder.AddAttribute(3, nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, e =>
{
ToastService.Warning("自定义 TreeViewItem", "测试 TreeViewItem 按钮点击事件");
}));
builder.CloseComponent();
}
}

/// <summary>
/// 获得属性方法
/// </summary>
Expand Down
Loading
Loading