نمایش ساختارهای درختی در Blazor
نویسنده: وحید نصیری
تاریخ: ۱۴۰۲/۰۵/۰۸ ۱۳:۲۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
namespace BlazorTreeView.ViewModels;
public class Comment
{
public IList<Comment> Comments = new List<Comment>();
public string? Text { set; get; }
} using BlazorTreeView.ViewModels;
namespace BlazorTreeView.Pages;
public partial class TreeView
{
private IReadOnlyDictionary<string, object> ChildrenHtmlAttributes { get; } =
new Dictionary<string, object>(StringComparer.Ordinal)
{
{ "style", "list-style: none;" },
};
private IList<Comment> Comments { get; } =
new List<Comment>
{
new()
{
Text = "پاسخ یک",
},
new()
{
Text = "پاسخ دو",
Comments =
new List<Comment>
{
new()
{
Text = "پاسخ اول به پاسخ دو",
Comments =
new List<Comment>
{
new()
{
Text = "پاسخی به پاسخ اول پاسخ دو",
},
},
},
new()
{
Text = "پاسخ دوم به پاسخ دو",
},
},
},
new()
{
Text = "پاسخ سوم",
},
};
}
/// <summary>
/// A custom DntTreeView
/// </summary>
public partial class DntTreeView<TRecord>
{ /// <summary>
/// The treeview's self-referencing items
/// </summary>
[Parameter]
public IEnumerable<TRecord>? Items { set; get; } /// <summary>
/// The treeview item's template
/// </summary>
[Parameter]
public RenderFragment<TRecord>? ItemTemplate { set; get; } /// <summary>
/// The content displayed if the list is empty
/// </summary>
[Parameter]
public RenderFragment? EmptyContentTemplate { set; get; } public class Comment
{
public IList<Comment> Comments = new List<Comment>();
public string? Text { set; get; }
} /// <summary>
/// The property which returns the children items
/// </summary>
[Parameter]
public Expression<Func<TRecord, IEnumerable<TRecord>>>? ChildrenSelector { set; get; } <DntTreeView
TRecord="Comment"
Items="Comments"
ChildrenSelector="m => m.Comments" public partial class DntTreeView<TRecord>
{
private Expression? _lastCompiledExpression;
internal Func<TRecord, IEnumerable<TRecord>>? CompiledChildrenSelector { private set; get; }
// ...
protected override void OnParametersSet()
{
if (_lastCompiledExpression != ChildrenSelector)
{
CompiledChildrenSelector = ChildrenSelector?.Compile();
_lastCompiledExpression = ChildrenSelector;
}
}
} @namespace BlazorTreeView.Pages.Components
@typeparam TRecord
@if (Items is null || !Items.Any())
{
@EmptyContentTemplate
}
else
{
<CascadingValue Value="this">
<ul @attributes="AdditionalAttributes">
@foreach (var item in Items)
{
<DntTreeViewChildrenItem TRecord="TRecord" ParentItem="item"/>
}
</ul>
</CascadingValue>
} @namespace BlazorTreeView.Pages.Components
@typeparam TRecord
<li @attributes="@SafeOwnerTreeView.ChildrenHtmlAttributes" @key="ParentItem?.GetHashCode()">
@if (SafeOwnerTreeView.ItemTemplate is not null && ParentItem is not null)
{
@SafeOwnerTreeView.ItemTemplate(ParentItem)
}
@if (Children is not null)
{
<ul>
@foreach (var item in Children)
{
<DntTreeViewChildrenItem TRecord="TRecord" ParentItem="item"/>
}
</ul>
}
</li> /// <summary>
/// A custom DntTreeView
/// </summary>
public partial class DntTreeViewChildrenItem<TRecord>
{
/// <summary>
/// Defines the owner of this component.
/// </summary>
[CascadingParameter]
public DntTreeView<TRecord>? OwnerTreeView { get; set; }
private DntTreeView<TRecord> SafeOwnerTreeView =>
OwnerTreeView ??
throw new InvalidOperationException("`DntTreeViewChildrenItem` should be placed inside of a `DntTreeView`.");
/// <summary>
/// Nested parent item to display
/// </summary>
[Parameter]
public TRecord? ParentItem { set; get; }
private IEnumerable<TRecord>? Children =>
ParentItem is null || SafeOwnerTreeView.CompiledChildrenSelector is null
? null
: SafeOwnerTreeView.CompiledChildrenSelector(ParentItem);
} <div class="card" dir="rtl">
<div class="card-header">
DntTreeView
</div>
<div class="card-body">
<DntTreeView
TRecord="Comment"
Items="Comments"
ChildrenSelector="m => m.Comments"
style="list-style: none;"
ChildrenHtmlAttributes="ChildrenHtmlAttributes">
<ItemTemplate Context="record">
<div class="card mb-1">
<div class="card-body">
<span>@record.Text</span>
</div>
</div>
</ItemTemplate>
<EmptyContentTemplate>
<div class="alert alert-warning">
There is no item to display!
</div>
</EmptyContentTemplate>
</DntTreeView>
</div>
</div> //َAgent Entity
public class Agent:BaseEntity,ISoftDeleteModel { public int AgentId { get; set; } [MaxLength(300, ErrorMessage = "{0} حداکثر میتواند شامل {1} کاراکتر باشد")] public string Title { get; set; } public int Sort { get; set; } public bool IsDisplayed { get; set; } = true; [ForeignKey("Parent")] public int? ParentID { get; set; } public bool IsDeleted { get; set; } [InverseProperty("AgentSend")] public ICollection<LetterAgent> LetterAgentsSend { get; set; } [InverseProperty("AgentReceive")] public ICollection<LetterAgent> LetterAgentsReceive { get; set; } public ICollection<UserAgent> UserAgents { get; set; } public Agent? Parent { get; set; } public ICollection<Agent>? SubGroups { get; set; } }
//SelfReferential
modelBuilder.Entity<Agent>(entity =>
{
entity.HasIndex(e => e.ParentID);
entity.HasOne(d => d.Parent)
.WithMany(p => p.SubGroups)
.HasForeignKey(d => d.ParentID);
}); <DntTreeView
TRecord="AgentDTO"
Items="Comments"
ChildrenSelector="m => m.SubGroups"
style="list-style: none;"
ChildrenHtmlAttributes="ChildrenHtmlAttributes">
<ItemTemplate Context="record">
<div class="card mb-1">
<div class="card-body">
<span>@record.Title</span>
</div>
</div>
</ItemTemplate>
<EmptyContentTemplate>
<div class="alert alert-warning">
There is no item to display!
</div>
</EmptyContentTemplate>
</DntTreeView>