Enterprise-level component library based on Bootstrap and Blazor

star nuget master download license repo commit

Table 表格

常用于大数据单表维护

通过 OnQueryAsync 回调获得数据集合

Demo
Loading...

使用 List<TItem> 泛型集合作为数据源时,需要按照下面的步骤进行设置

1. 设置数据源
设置 Table 组件的 Items 属性或者 OnQueryAsync 回调委托方法

protected override void OnInitialized()
{
    base.OnInitialized();

    Items = Foo.GenerateFoo(Localizer);
}

2. 处理新建逻辑
设置 OnAddAsync 回调委托函数处理 新建 逻辑

private Task<Foo> OnAddAsync()
{
    // 此处代码为示例代码
    var foo = new Foo() { DateTime = DateTime.Now, Address = $"自定义地址  {DateTime.Now.Second}" };
    Items.Insert(0, foo);

    // 输出日志信息
    Trace.Log($"集合值变化通知 列: {Items.Count} - 类型: Add");
    return Task.FromResult(foo);
}

3. 处理删除逻辑
设置 OnDeleteAsync 回调委托函数处理 删除 逻辑

private Task<bool> OnDeleteAsync(IEnumerable<Foo> items)
{
    // 此处代码为示例代码
    Items.RemoveAll(i => items.Contains(i));

    // 输出日志信息
    Trace.Log($"集合值变化通知 列: {Items.Count} - 类型: Delete");
    return Task.FromResult(true);
}

4. 处理更新逻辑
设置 OnSaveAsync 回调委托函数处理单元格 更新 逻辑
组件内部所有单元格编辑更新后会自动触发 OnSaveAsync 回调委托,参数是当前更新模型 TItem

private Task<bool> OnDeleteAsync(Foo item, ItemChangedType changedType)
{
    // 此处代码为示例代码
    Trace.Log($"单元格变化通知 类: Foo - 值: 单元格");
    return Task.FromResult(true);
}

高级用法

Demo
  • IsFixedHeader 固定表头 高度设定为 Height="500px"
  • Name 不可编辑显示头像
Loading...
@page "/tables/excel"

<h3>Table 表格</h3>

<h4>常用于大数据单表维护</h4>

<Block Title="绑定集合" Introduction="通过 <code>OnQueryAsync</code> 回调获得数据集合" Name="OnQuery">
    <Table TItem="Foo" ShowColumnList="true"
           IsExcel="true" IsPagination="true" PageItemsSource="@PageItemsSource"
           OnQueryAsync="@OnQueryAsync" OnAddAsync="@OnAddAsync" OnSaveAsync="@OnSaveAsync" OnDeleteAsync="@OnDeleteAsync">
        <TableColumns>
            <TableColumn @bind-Field="@context.DateTime" Width="180" />
            <TableColumn @bind-Field="@context.Name" />
            <TableColumn @bind-Field="@context.Address" Readonly="true" />
            <TableColumn @bind-Field="@context.Education" />
            <TableColumn @bind-Field="@context.Count" Editable="false" Align="Alignment.Right" />
            <TableColumn @bind-Field="@context.Complete" Align="Alignment.Center" />
        </TableColumns>
    </Table>

    <BlockLogger @ref="Trace" class="mt-3" />
</Block>

<p class="mt-3">使用 <code>List&lt;TItem&gt;</code> 泛型集合作为数据源时,需要按照下面的步骤进行设置</p>

<p>
    <div class="code-label">1. 设置数据源</div>
    <div class="mt-2">设置 <code>Table</code> 组件的 <code>Items</code> 属性或者 <code>OnQueryAsync</code> 回调委托方法</div>
</p>

<Pre>protected override void OnInitialized()
{
    base.OnInitialized();

    Items = Foo.GenerateFoo(Localizer);
}</Pre>

<p>
    <div class="code-label">2. 处理新建逻辑</div>
    <div class="mt-2">设置 <code>OnAddAsync</code> 回调委托函数处理 <b>新建</b> 逻辑</div>
</p>

<Pre>private Task&lt;Foo&gt; OnAddAsync()
{
    // 此处代码为示例代码
    var foo = new Foo() { DateTime = DateTime.Now, Address = $"自定义地址  {DateTime.Now.Second}" };
    Items.Insert(0, foo);

    // 输出日志信息
    Trace.Log($"集合值变化通知 列: {Items.Count} - 类型: Add");
    return Task.FromResult(foo);
}</Pre>

<p>
    <div class="code-label">3. 处理删除逻辑</div>
    <div class="mt-2">设置 <code>OnDeleteAsync</code> 回调委托函数处理 <b>删除</b> 逻辑</div>
</p>

<Pre>private Task&lt;bool&gt; OnDeleteAsync(IEnumerable&lt;Foo&gt; items)
{
    // 此处代码为示例代码
    Items.RemoveAll(i => items.Contains(i));

    // 输出日志信息
    Trace.Log($"集合值变化通知 列: {Items.Count} - 类型: Delete");
    return Task.FromResult(true);
}</Pre>

<p>
    <div class="code-label">4. 处理更新逻辑</div>
    <div class="mt-2">设置 <code>OnSaveAsync</code> 回调委托函数处理单元格 <b>更新</b> 逻辑</div>
    <div class="mt-2">组件内部所有单元格编辑更新后会自动触发 <code>OnSaveAsync</code> 回调委托,参数是当前更新模型 <code>TItem</code></div>
</p>

<Pre>private Task&lt;bool&gt; OnDeleteAsync(Foo item, ItemChangedType changedType)
{
    // 此处代码为示例代码
    Trace.Log($"单元格变化通知 类: Foo - 值: 单元格");
    return Task.FromResult(true);
}</Pre>

<Block Title="通过编辑模板单独控制单元格渲染方式" Introduction="高级用法" Name="CellRender">
    <ul class="ul-demo">
        <li><code>IsFixedHeader</code> 固定表头 高度设定为 <code>Height="500px"</code></li>
        <li><code>Name</code> 不可编辑显示头像</li>
    </ul>
    <Table TItem="Foo" Items="@Items" IsBordered="true" IsExcel="true" IsFixedHeader="true" Height="500">
        <TableColumns>
            <TableColumn @bind-Field="@context.Name" Width="200">
                <EditTemplate Context="value">
                    @{
                        var row = (Foo)value;
                    }
                    <div class="d-flex disabled">
                        <div>
                            <img src="@Foo.GetAvatarUrl(row.Id)" class="bb-avatar" />
                        </div>
                        <div class="ps-2">
                            <div>@row.Name</div>
                            <div class="bb-sub">@GetTitle(row.Id)</div>
                        </div>
                    </div>
                </EditTemplate>
            </TableColumn>
            <TableColumn @bind-Field="@context.Address" />
            <TableColumn @bind-Field="@context.Education" Width="160" />
            <TableColumn @bind-Field="@context.Count" Width="160">
                <EditTemplate Context="value">
                    @{
                        var row = (Foo)value;
                    }
                    <div class="disabled">
                        <div>@row.Count %</div>
                        <Progress Value="@row.Count" Color="@Foo.GetProgressColor(row.Count)"></Progress>
                    </div>
                </EditTemplate>
            </TableColumn>
            <TableColumn @bind-Field="@context.Complete" Align="Alignment.Center" Width="80" />
        </TableColumns>
    </Table>
</Block>
// 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.Components;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;

namespace BootstrapBlazor.Shared.Pages.Table
{
    /// <summary>
    /// 
    /// </summary>
    partial class TablesExcel
    {
        [Inject]
        [NotNull]
        private IStringLocalizer<Foo>? Localizer { get; set; }

        [Inject]
        [NotNull]
        private IStringLocalizer<Tables>? TablesLocalizer { get; set; }

        [NotNull]
        private BlockLogger? Trace { get; set; }

        /// <summary>
        /// OnInitialized 方法
        /// </summary>
        protected override void OnInitialized()
        {
            base.OnInitialized();

            Items = Foo.GenerateFoo(Localizer);
        }

        // 绑定数据源代码
        private static IEnumerable<int> PageItemsSource => new int[] { 10, 20, 40 };

        [NotNull]
        private List<Foo>? Items { get; set; }

        private static readonly ConcurrentDictionary<Type, Func<IEnumerable<Foo>, string, SortOrder, IEnumerable<Foo>>> SortLambdaCache = new();

        private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
        {
            IEnumerable<Foo> items = Items;

            // 过滤
            var isFiltered = false;
            if (options.Filters.Any())
            {
                items = items.Where(options.Filters.GetFilterFunc<Foo>());
                isFiltered = true;
            }

            // 排序
            var isSorted = false;
            if (!string.IsNullOrEmpty(options.SortName))
            {
                var invoker = SortLambdaCache.GetOrAdd(typeof(Foo), key => LambdaExtensions.GetSortLambda<Foo>().Compile());
                items = invoker(items, options.SortName, options.SortOrder);
                isSorted = true;
            }

            // 设置记录总数
            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,
                IsSorted = isSorted,
                IsFiltered = isFiltered,
                IsSearch = true
            });
        }

        private Task<Foo> OnAddAsync()
        {
            // Excel 模式下新建要求更改数据源
            var foo = new Foo() { DateTime = DateTime.Now, Address = $"自定义地址  {DateTime.Now.Second}" };
            Items.Insert(0, foo);

            // 输出日志信息
            Trace.Log($"集合值变化通知 列: {Items.Count} - 类型: Add");
            return Task.FromResult(foo);
        }

        private Task<bool> OnSaveAsync(Foo item, ItemChangedType changedType)
        {
            // 对象已经更新
            // 输出日志信息
            Trace.Log($"单元格变化通知 类: Foo - 值: 单元格");
            return Task.FromResult(true);
        }

        private Task<bool> OnDeleteAsync(IEnumerable<Foo> items)
        {
            Items.RemoveAll(i => items.Contains(i));

            // 输出日志信息
            Trace.Log($"集合值变化通知 列: {Items.Count} - 类型: Delete");
            return Task.FromResult(true);
        }

        private ConcurrentDictionary<int, string> TitleCache { get; } = new();

        private string GetTitle(int id) => TitleCache.GetOrAdd(id, key => Foo.GetTitle());
    }
}

B 站相关视频链接

[传送门]

交流群

QQ Group:BootstrapAdmin & Blazor 795206915 675147445 Welcome to join the group discussion
Themes
Bootstrap
Motronic
Ant Design (完善中)
LayUI (完善中)
An error has occurred. This application may no longer respond until reloaded. Reload