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

[TreeView] Add Items and LazyLoadItems properties #1945

Merged
merged 30 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d3a40aa
Add ITreeViewItem
dvoituron Apr 24, 2024
ba551a4
Merge branch 'dev' into users/dvoituron/treeview-items
dvoituron Apr 25, 2024
6c6ce40
Add Icons and Disabled property
dvoituron Apr 25, 2024
39b158a
Add ItemTemplate
dvoituron Apr 25, 2024
5764aa3
Fix indentations
dvoituron Apr 25, 2024
baac1ef
Add Loading item
dvoituron Apr 26, 2024
6459743
Fix sample
dvoituron Apr 26, 2024
8f1560b
Remove using
dvoituron Apr 26, 2024
384ef36
Merge branch 'dev' into users/dvoituron/treeview-items
dvoituron Apr 26, 2024
693f2d4
Flag RenderCollapsedNodes as Obsolete
dvoituron Apr 27, 2024
fe37f70
Merge branch 'dev' into users/dvoituron/treeview-items
vnbaaij Apr 30, 2024
f75e0e1
Merge branch 'dev' into users/dvoituron/treeview-items
dvoituron May 10, 2024
a5319d5
Merge branch 'users/dvoituron/treeview-items' of github.com-perso:mic…
dvoituron May 10, 2024
38209ce
Add TreeViewItem object
dvoituron May 10, 2024
77090d8
Add Id
dvoituron May 10, 2024
7677d9c
Add OnExpandedAsync
dvoituron May 10, 2024
49e2645
Add Expanded property
dvoituron May 10, 2024
70b3749
Add SelectedItem
dvoituron May 10, 2024
00cb264
Update doc
dvoituron May 11, 2024
dff8661
Add Unit Tests
dvoituron May 11, 2024
2be9b14
Update SelectedItem property
dvoituron May 11, 2024
3640268
Add Unit Tests
dvoituron May 11, 2024
1db93b7
Add Unit Tests
dvoituron May 11, 2024
38b530f
Add Unit Tests
dvoituron May 11, 2024
7a60520
Add Unit Tests
dvoituron May 11, 2024
b8d02d1
Merge branch 'dev' into users/dvoituron/treeview-items
dvoituron May 14, 2024
ad90482
Merge branch 'dev' into users/dvoituron/treeview-items
dvoituron May 15, 2024
60a396c
Update PR comments
dvoituron May 15, 2024
01ccc99
Merge branch 'users/dvoituron/treeview-items' of github.com-perso:mic…
dvoituron May 15, 2024
4dc141c
Merge branch 'dev' into users/dvoituron/treeview-items
vnbaaij May 16, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -8489,6 +8489,16 @@
<member name="M:Microsoft.FluentUI.AspNetCore.Components.Components.Tooltip.TooltipService.Remove(System.Guid)">
<inheritdoc cref="M:Microsoft.FluentUI.AspNetCore.Components.Components.Tooltip.ITooltipService.Remove(System.Guid)"/>
</member>
<member name="M:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.#ctor">
<summary>
Initializes a new instance of the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem"/> class.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.Items">
<summary>
Gets or sets the list of sub-items to bind to the tree item
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.Text">
<summary>
Gets or sets the text of the tree item
Expand Down Expand Up @@ -8537,6 +8547,20 @@
be selected when it is created.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.IconCollapsed">
<summary>
Gets or sets the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Icon"/> displayed at the start of tree item,
when the node is collapsed.
If this icon is not set, the <see cref="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.IconExpanded"/> will be used.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.IconExpanded">
<summary>
Gets or sets the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Icon"/> displayed at the start of tree item,
when the node is expanded.
If this icon is not set, the <see cref="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.IconCollapsed"/> will be used.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeItem.Owner">
<summary>
Gets or sets the owning FluentTreeView
Expand Down Expand Up @@ -8581,6 +8605,46 @@
item within the tree.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeView.ItemTemplate">
<summary>
Gets or sets the template for rendering tree items.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTreeView.LazyLoadItems">
<summary>
Gets or sets whether the tree should use lazy loading when expanding nodes
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ITreeViewItem.Text">
<summary>
Gets or sets the text of the tree item
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ITreeViewItem.Items">
<summary>
Gets or sets the sub-items of the tree item
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ITreeViewItem.IconCollapsed">
<summary>
Gets or sets the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Icon"/> displayed at the start of tree item,
when the node is collapsed.
If this icon is not set, the <see cref="P:Microsoft.FluentUI.AspNetCore.Components.ITreeViewItem.IconExpanded"/> will be used.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ITreeViewItem.IconExpanded">
<summary>
Gets or sets the <see cref="T:Microsoft.FluentUI.AspNetCore.Components.Icon"/> displayed at the start of tree item,
when the node is expanded.
If this icon is not set, the <see cref="P:Microsoft.FluentUI.AspNetCore.Components.ITreeViewItem.IconCollapsed"/> will be used.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.ITreeViewItem.Disabled">
<summary>
When true, the control will be immutable by user interaction.
See <see href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled">disabled</see> HTML attribute for more information.
</summary>
</member>
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentWizard.ClassValue">
<summary />
</member>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<FluentTreeView Items="@Items" LazyLoadItems="true">
<ItemTemplate>
@context.Text
<span style="color: var(--accent-fill-rest); margin: 0 4px;">
@(context.Items == null ? "" : $"[{context.Items.Count()}]")
</span>
</ItemTemplate>
</FluentTreeView>

Total items: @Count

@code
{
private Icon IconCollapsed = new Icons.Regular.Size20.Folder();
private Icon IconExpanded = new Icons.Regular.Size20.FolderOpen();

private int Count = -1;
private IEnumerable<ITreeViewItem>? Items = new List<ITreeViewItem>();

protected override void OnInitialized()
{
Items = CreateTree(maxLevel: 5, maxItemsPerLevel: 12).Items;
}

// Recursive method to create tree
public TreeViewItem CreateTree(int maxLevel, int maxItemsPerLevel, int level = 0)
{
Count++;

int nbItems = Random.Shared.Next(maxItemsPerLevel - 3, maxItemsPerLevel);

var treeItem = new TreeViewItem
{
Text = $"Item {Count}",
Disabled = Count % 7 == 0,
IconCollapsed = IconCollapsed,
IconExpanded = IconExpanded,
Items = level == maxLevel
? null
: new List<TreeViewItem>(Enumerable.Range(1, nbItems)
.Select(i => CreateTree(maxLevel, maxItemsPerLevel, level + 1)))
};
return treeItem;
}


public class TreeViewItem : ITreeViewItem
{
public string Text { get; set; } = "";
public IEnumerable<ITreeViewItem>? Items { get; set; }
public Icon? IconCollapsed { get; set; }
public Icon? IconExpanded { get; set; }
public bool Disabled { get; set; }
}
}
2 changes: 2 additions & 0 deletions examples/Demo/Shared/Pages/TreeView/TreeViewPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

<DemoSection Title="Default with event handling" Component="@typeof(TreeViewDefault)"/>

<DemoSection Title="With Items" Component="@typeof(TreeViewWithItems)" />

<DemoSection Title="Flat tree" Component="@typeof(TreeViewFlat)"/>

<DemoSection Title="Some expanded" Component="@typeof(TreeViewSomeExpanded)"/>
Expand Down
26 changes: 25 additions & 1 deletion src/Core/Components/TreeView/FluentTreeItem.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@namespace Microsoft.FluentUI.AspNetCore.Components
@inherits FluentComponentBase
<fluent-tree-item @ref=Element
class="@Class"
Expand All @@ -12,9 +12,33 @@
@onselectedchange="@HandleSelectedChangeAsync"
@onexpandedchange="@HandleExpandedChangeAsync"
@attributes="AdditionalAttributes">

@if (!string.IsNullOrWhiteSpace(Text))
{
<span class="treeitem-text">@Text</span>
}

@if (IconExpanded != null || IconCollapsed != null)
{
<FluentIcon Value="@(Expanded ? (IconExpanded ?? IconCollapsed) : (IconCollapsed ?? IconExpanded))" Slot="start" />
}

@ChildContent

@if (Items != null)
{
@if (Owner.LazyLoadItems && Items.Any() && !Expanded)
{
@* Lazy loading required a "fake" sub-item to simulate the [+] *@
<fluent-tree-item>@FluentTreeView.LoadingMessage</fluent-tree-item>
}
else
{
foreach (var item in Items)
{
@FluentTreeItem.GetFluentTreeItem(Owner, item)
}
}
}

</fluent-tree-item>
66 changes: 61 additions & 5 deletions src/Core/Components/TreeView/FluentTreeItem.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ public partial class FluentTreeItem : FluentComponentBase, IDisposable
{
private bool _disposed;

/// <summary>
/// Initializes a new instance of the <see cref="FluentTreeItem"/> class.
/// </summary>
public FluentTreeItem()
{
Id = Identifier.NewId();
}

/// <summary>
/// Gets or sets the list of sub-items to bind to the tree item
/// </summary>
[Parameter]
public IEnumerable<ITreeViewItem>? Items { get; set; }
dvoituron marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Gets or sets the text of the tree item
/// </summary>
Expand Down Expand Up @@ -63,6 +77,22 @@ public partial class FluentTreeItem : FluentComponentBase, IDisposable
[Parameter]
public bool InitiallySelected { get; set; }

/// <summary>
/// Gets or sets the <see cref="Icon"/> displayed at the start of tree item,
/// when the node is collapsed.
/// If this icon is not set, the <see cref="IconExpanded"/> will be used.
/// </summary>
[Parameter]
public Icon? IconCollapsed { get; set; }

/// <summary>
/// Gets or sets the <see cref="Icon"/> displayed at the start of tree item,
/// when the node is expanded.
/// If this icon is not set, the <see cref="IconCollapsed"/> will be used.
/// </summary>
[Parameter]
public Icon? IconExpanded { get; set; }

/// <summary>
/// Gets or sets the owning FluentTreeView
/// </summary>
Expand All @@ -75,11 +105,6 @@ public partial class FluentTreeItem : FluentComponentBase, IDisposable
/// </summary>
public bool Collapsed => !Expanded;

public FluentTreeItem()
{
Id = Identifier.NewId();
}

void IDisposable.Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Expand Down Expand Up @@ -142,6 +167,7 @@ private async Task HandleExpandedChangeAsync(TreeChangeEventArgs args)
}

Expanded = args.Expanded.Value;

if (ExpandedChanged.HasDelegate)
{
await ExpandedChanged.InvokeAsync(Expanded);
Expand All @@ -167,4 +193,34 @@ private async Task HandleSelectedChangeAsync(TreeChangeEventArgs args)
await tree.ItemSelectedChangeAsync(this);
}
}

internal static RenderFragment GetFluentTreeItem(FluentTreeView owner, ITreeViewItem item)
{
RenderFragment fluentTreeItem = builder =>
{
int i = 0;
builder.OpenComponent<FluentTreeItem>(i++);
builder.AddAttribute(i++, "Items", item.Items);
builder.AddAttribute(i++, "Text", owner.ItemTemplate == null ? item.Text : string.Empty);
builder.AddAttribute(i++, "Disabled", item.Disabled);
builder.AddAttribute(i++, "IconCollapsed", item.IconCollapsed);
builder.AddAttribute(i++, "IconExpanded", item.IconExpanded);

if (owner.ItemTemplate != null)
{
builder.AddAttribute(i++, "ChildContent", owner.ItemTemplate(item));
}

builder.CloseComponent();

//builder.AddAttribute(i++, "Expanded", Expanded);
//builder.AddAttribute(i++, "ExpandedChanged", EventCallback.Factory.Create<bool>(this, HandleExpandedChangeAsync));
//builder.AddAttribute(i++, "Selected", Selected);
//builder.AddAttribute(i++, "SelectedChanged", EventCallback.Factory.Create<bool>(this, HandleSelectedChangeAsync));
//builder.AddAttribute(i++, "InitiallyExpanded", InitiallyExpanded);
//builder.AddAttribute(i++, "InitiallySelected", InitiallySelected); builder.CloseComponent();
};

return fluentTreeItem;
}
}
10 changes: 9 additions & 1 deletion src/Core/Components/TreeView/FluentTreeView.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@namespace Microsoft.FluentUI.AspNetCore.Components
@namespace Microsoft.FluentUI.AspNetCore.Components
@inherits FluentComponentBase
<CascadingValue Value="this" IsFixed="true">
<fluent-tree-view @ref=Element
Expand All @@ -8,5 +8,13 @@
@onselectedchange="@HandleCurrentSelectedChangeAsync"
@attributes="AdditionalAttributes">
@ChildContent

@if (Items != null)
{
foreach (var item in Items)
{
@FluentTreeItem.GetFluentTreeItem(this, item)
}
}
</fluent-tree-view>
</CascadingValue>
19 changes: 19 additions & 0 deletions src/Core/Components/TreeView/FluentTreeView.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public partial class FluentTreeView : FluentComponentBase, IDisposable
private readonly Debouncer _currentSelectedChangedDebouncer = new();
private bool _disposed;

public static string LoadingMessage = "Loading...";

[Parameter]
public IEnumerable<ITreeViewItem>? Items { get; set; }

/// <summary>
/// Gets or sets whether the tree should render nodes under collapsed items
/// Defaults to false
Expand Down Expand Up @@ -49,6 +54,18 @@ public partial class FluentTreeView : FluentComponentBase, IDisposable
[Parameter]
public EventCallback<FluentTreeItem> OnExpandedChange { get; set; }

/// <summary>
/// Gets or sets the template for rendering tree items.
/// </summary>
[Parameter]
public RenderFragment<ITreeViewItem>? ItemTemplate { get; set; }

/// <summary>
/// Gets or sets whether the tree should use lazy loading when expanding nodes
/// </summary>
dvoituron marked this conversation as resolved.
Show resolved Hide resolved
[Parameter]
public bool LazyLoadItems { get; set; } = false;

[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(TreeChangeEventArgs))]
public FluentTreeView()
{
Expand Down Expand Up @@ -91,6 +108,8 @@ internal void Unregister(FluentTreeItem fluentTreeItem)

private async Task HandleCurrentSelectedChangeAsync(TreeChangeEventArgs args)
{
Console.WriteLine("HandleCurrentSelectedChangeAsync");

if (!_allItems.TryGetValue(args.AffectedId!, out FluentTreeItem? treeItem))
{
return;
Expand Down
38 changes: 38 additions & 0 deletions src/Core/Components/TreeView/ITreeViewItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// ------------------------------------------------------------------------
// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
// ------------------------------------------------------------------------

namespace Microsoft.FluentUI.AspNetCore.Components;

public interface ITreeViewItem
{
/// <summary>
/// Gets or sets the text of the tree item
/// </summary>
public string Text { get; set; }

/// <summary>
/// Gets or sets the sub-items of the tree item
/// </summary>
public IEnumerable<ITreeViewItem>? Items { get; set; }

/// <summary>
/// Gets or sets the <see cref="Icon"/> displayed at the start of tree item,
/// when the node is collapsed.
/// If this icon is not set, the <see cref="IconExpanded"/> will be used.
/// </summary>
public Icon? IconCollapsed { get; set; }

/// <summary>
/// Gets or sets the <see cref="Icon"/> displayed at the start of tree item,
/// when the node is expanded.
/// If this icon is not set, the <see cref="IconCollapsed"/> will be used.
/// </summary>
public Icon? IconExpanded { get; set; }

/// <summary>
/// When true, the control will be immutable by user interaction.
/// See <see href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled">disabled</see> HTML attribute for more information.
/// </summary>
public bool Disabled { get; set; }
}
Loading