
Display detail line function
Used to display parent-child relationship table data
Set the detail row content by setting the DetailRowTemplate
template
Demo
In the detail row, another field education
of the binding row is displayed in the form of ordinary text
Set the detail behavior sub-table data by setting the DetailRowTemplate
template
Demo
Another Table
component is nested in the detail row. Since each row must be associated with sub-table data, for performance reasons, this function adopts the lazy loading
mode. , that is, after clicking the expand button, the nested Table
is filled with data, and the ShowDetailRow
callback delegate can control whether each row displays the detail row. In this example, the Complete
attribute to control whether to display the detail line, you can test this function by turning the page
Set the content of the detail row by setting the Height
template after the header is fixed
Demo
In this example, after the header is fixed, the detail line function is enabled
Set the detail row content by setting the DetailRowTemplate
template
Demo
In this example, the Tab
component is used in the detail row to split the data into two TabItem
contents again to demonstrate the data splitting again
Data source is DataTable
Demo
@page "/tables/detail"
<h3>@LocalizerDetailRow["Title"]</h3>
<h4>@LocalizerDetailRow["Desc"]</h4>
<DemoBlock Title="@LocalizerDetailRow["DetailRowTemplateTitle"]" Introduction="@LocalizerDetailRow["DetailRowTemplateIntro"]" Name="IsDetails">
<p>@((MarkupString)LocalizerDetailRow["DetailRowTemplateP"].Value)</p>
<Table TItem="Foo" @ref="@Table"
IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true" IsDetails="IsDetails"
ShowToolbar="true" ShowDefaultButtons="false" ShowRefresh="false" OnDoubleClickRowCallback="OnDoubleClickRowCallback()!"
OnQueryAsync="@OnQueryAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" Width="100" />
<TableColumn @bind-Field="@context.Address" />
<TableColumn @bind-Field="@context.Count" />
</TableColumns>
<DetailRowTemplate>
<div>@LocalizerDetailRow["EducationText"] @typeof(EnumEducation).ToDescriptionString(context.Education.ToString())</div>
</DetailRowTemplate>
</Table>
<Button Text="@DetailText" OnClick="OnClickDetailRow" class="mt-3"></Button>
</DemoBlock>
<DemoBlock Title="@LocalizerDetailRow["DetailRowTemplate2Title"]" Introduction="@LocalizerDetailRow["DetailRowTemplate2Intro"]" Name="ShowDetailRow">
<p>@((MarkupString)LocalizerDetailRow["DetailRowTemplate2P"].Value)</p>
<Table TItem="Foo"
IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true"
ShowToolbar="true" ShowDefaultButtons="false"
OnQueryAsync="@OnQueryAsync" ShowDetailRow="ShowDetailRow">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" Width="100" />
<TableColumn @bind-Field="@context.Address" />
<TableColumn @bind-Field="@context.Count" />
</TableColumns>
<DetailRowTemplate>
<Table TItem="DetailRow" IsBordered="true" ShowToolbar="false" Items="@GetDetailDataSource(context)">
<TableColumns Context="Detail">
<TableColumn @bind-Field="@Detail.Name" />
<TableColumn @bind-Field="@Detail.DateTime" Width="180" />
<TableColumn @bind-Field="@Detail.Complete" Width="70" />
</TableColumns>
</Table>
</DetailRowTemplate>
</Table>
</DemoBlock>
<DemoBlock Title="@LocalizerDetailRow["HeightTitle"]" Introduction="@LocalizerDetailRow["HeightIntro"]" Name="Height">
<p>@LocalizerDetailRow["HeightP"]</p>
<Table TItem="Foo" Height="400" IsFixedHeader="true"
IsStriped="true" IsBordered="true"
ShowToolbar="true" ShowDefaultButtons="false"
OnQueryAsync="@OnQueryAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" Width="100" />
<TableColumn @bind-Field="@context.Address" />
<TableColumn @bind-Field="@context.Count" />
</TableColumns>
<DetailRowTemplate>
<div>@LocalizerDetailRow["EducationText"] @typeof(EnumEducation).ToDescriptionString(context.Education.ToString())</div>
</DetailRowTemplate>
</Table>
</DemoBlock>
<DemoBlock Title="@LocalizerDetailRow["DetailRowTemplate3Title"]" Introduction="@LocalizerDetailRow["DetailRowTemplate3Intro"]" Name="DetailRowTemplate3">
<p>@((MarkupString)LocalizerDetailRow["DetailRowTemplate3P"].Value)</p>
<Table TItem="Foo" IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true"
ShowToolbar="true" ShowDefaultButtons="false"
OnQueryAsync="@OnQueryAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Width="180" />
<TableColumn @bind-Field="@context.Name" Width="100" />
<TableColumn @bind-Field="@context.Address" />
<TableColumn @bind-Field="@context.Count" />
</TableColumns>
<DetailRowTemplate>
<Tab>
<TabItem Text="明细数据">
<Table TItem="DetailRow" IsBordered="true" ShowToolbar="false" Items="@GetDetailDataSource(context)" AutoGenerateColumns="true" />
</TabItem>
<TabItem Text="@LocalizerDetailRow["TabItemText"]">
<div>@LocalizerDetailRow["EducationText"] @typeof(EnumEducation).ToDescriptionString(context.Education.ToString())</div>
</TabItem>
</Tab>
</DetailRowTemplate>
</Table>
</DemoBlock>
<DemoBlock Title="@LocalizerDetailRow["DynamicTitle"]" Introduction="@LocalizerDetailRow["DynamicIntro"]" Name="Excel">
<Table TItem="DynamicObject" DynamicContext="DataTableDynamicContext"
IsStriped="true" IsBordered="true" IsExcel="true"
ShowToolbar="true" ShowDefaultButtons="false">
<DetailRowTemplate>
@{
var detailContext = GetDetailDataTableDynamicContext(context);
}
<div class="p-2 w-100">
<Table TItem="DynamicObject" DynamicContext="detailContext" IsStriped="true" IsBordered="true" IsExcel="true">
</Table>
</div>
</DetailRowTemplate>
</Table>
</DemoBlock>
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Shared.Services;
using System.Collections.Concurrent;
using System.ComponentModel;
namespace BootstrapBlazor.Shared.Samples.Table;
/// <summary>
///
/// </summary>
public sealed partial class TablesDetailRow
{
private ConcurrentDictionary<string, List<DetailRow>> Cache { get; } = new();
private static readonly Random random = new();
private static IEnumerable<int> PageItemsSource => new int[] { 4, 10, 20 };
[NotNull]
private List<Foo>? Items { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<Foo>? Localizer { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<TablesDetailRow>? LocalizerDetailRow { get; set; }
[NotNull]
private string? DetailText { get; set; }
[Inject]
[NotNull]
private MockDataTableDynamicService? DataTableDynamicService { get; set; }
[NotNull]
private Table<Foo>? Table { get; set; }
private DataTableDynamicContext? DataTableDynamicContext { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
DetailText ??= LocalizerDetailRow[$"{nameof(DetailText)}{!IsDetails}"];
Items = Foo.GenerateFoo(Localizer);
DataTableDynamicContext = DataTableDynamicService.CreateContext();
}
private static List<DetailRow> GetDetailRowsByName(string name) => Enumerable.Range(1, 4).Select(i => new DetailRow()
{
Id = i,
Name = name,
DateTime = DateTime.Now.AddDays(i - 1),
Complete = random.Next(1, 100) > 50
}).ToList();
private Func<Foo, Task>? OnDoubleClickRowCallback()
{
Func<Foo, Task>? ret = null;
if (IsDetails)
{
ret = foo =>
{
Table.ExpandDetailRow(foo);
return Task.CompletedTask;
};
}
return ret;
}
private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
{
IEnumerable<Foo> items = Items;
// 设置记录总数
var total = items.Count();
// 内存分页
items = items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList();
return Task.FromResult(new QueryData<Foo>()
{
Items = items,
TotalCount = total
});
}
private bool IsDetails { get; set; } = true;
private void OnClickDetailRow()
{
DetailText = LocalizerDetailRow[$"{nameof(DetailText)}{IsDetails}"];
IsDetails = !IsDetails;
}
private List<DetailRow> GetDetailDataSource(Foo foo)
{
var cacheKey = foo.Name ?? "";
return Cache.GetOrAdd(cacheKey, key => GetDetailRowsByName(cacheKey));
}
private class DetailRow
{
/// <summary>
///
/// </summary>
[DisplayName("主键")]
public int Id { get; set; }
/// <summary>
///
/// </summary>
[DisplayName("培训课程")]
[AutoGenerateColumn(Order = 10)]
public string Name { get; set; } = "";
/// <summary>
///
/// </summary>
[DisplayName("日期")]
[AutoGenerateColumn(Order = 20, Width = 180)]
public DateTime DateTime { get; set; }
/// <summary>
///
/// </summary>
[DisplayName("是/否")]
[AutoGenerateColumn(Order = 30, Width = 70)]
public bool Complete { get; set; }
}
private static bool ShowDetailRow(Foo item) => item.Complete;
private DynamicObjectContext GetDetailDataTableDynamicContext(DynamicObject context) => DataTableDynamicService.CreateDetailContext(context);
}