
Excel-DataTable
Commonly used for large data sheet maintenance
Make the component render like Excel
by setting the table's IsExcel
property
Demo
When the binding is dynamic type in Excel
mode, TableColumn
cannot be used to set column properties. In this example, DynamicContext is used code> Instance object
DataTableDynamicContext
constructor to set
Set the column Items
value, and render the enum type into a Select
component
Demo
DataTableDynamicContext = new(UserData, (context, col) =>
{
if (col.GetFieldName() == nameof(Foo.Education))
{
col.ComponentType = typeof(Select<string>);
col.Items = typeof(EnumEducation).ToSelectList(new SelectedItem("", not set));
}
});
Education
column using the Select
componentThis example is used to test keyboard support in Excel
mode
Demo
Currently supported Tab
When using DatTable
as the data source, you need to follow the steps below to set
TItem
property of the Table
component to DynamicObject
DynamicContext
property of the Table
component to the DataTableDynamicContext
instanceprotected override void OnInitialized()
{
base.OnInitialized();
DataTableDynamicContext = new(UserData, (context, col) =>
{
// Set the Enum type to render to Select
if (col.GetFieldName() == nameof(Foo.Education))
{
col.ComponentType = typeof(Select<string>);
// Convert enum to List
col.Items = typeof(EnumEducation).ToSelectList(new SelectedItem("", Localizer["NullItemText"].Value));
}
});
}
DataRow
change logicOnChanged
callback delegate function to handle the New/Delete logicprotected override void OnInitialized()
{
DataTableDynamicContext.OnChanged = args =>
{
// output log information
Trace.Log($"# valueS: {args.Items.Count()} - type: {args.ChangedType}");
return Task.CompletedTask;
};
}
DataCell
change logicOnValueChanged
callback delegate function to handle the cell update logicprotected override void OnInitialized()
{
// Get built-in OnValueChanged callback
var method = DataTableDynamicContext.OnValueChanged;
DataTableDynamicContext.OnValueChanged = async (model, col, val) =>
{
// Invoke internally provided methods
if (method != null)
{
// The internal method updates the original data source DataTable
await method(model, col, val);
}
// output log information
Trace.Log($"Change Notification: {col.GetFieldName()} - Value: {val?.ToString()}");
};
}
@page "/tables/dynamicexcel"
<h3>@Localizer["H1"]</h3>
<h4>@Localizer["H2"]</h4>
<DemoBlock Title="@Localizer["P1"]" Introduction="@Localizer["P2"]" Name="Excel">
<p>@((MarkupString)Localizer["P3"].Value)</p>
<Table TItem="DynamicObject" DynamicContext="DataTableDynamicContext"
IsBordered="true" IsMultipleSelect="true" IsExcel="true" ShowToolbar="true">
</Table>
<BlockLogger @ref="Trace" class="mt-3" />
</DemoBlock>
<DemoBlock Title="@Localizer["P4"]" Introduction="@Localizer["P5"]" Name="Enum">
<Pre>DataTableDynamicContext = new(UserData, (context, col) =>
{
if (col.GetFieldName() == nameof(Foo.Education))
{
col.ComponentType = typeof(Select<string>);
col.Items = typeof(EnumEducation).ToSelectList(new SelectedItem("", @Localizer["P6"]));
}
});</Pre>
<div>
@((MarkupString)Localizer["P7"].Value)
</div>
</DemoBlock>
<DemoBlock Title="@Localizer["P8"]" Introduction="@Localizer["P9"]" Name="Keyboard">
<p>@Localizer["P10"] <kbd><i class="fa-solid fa-arrow-up"></i></kbd> <kbd><i class="fa-solid fa-arrow-down"></i></kbd> <kbd><i class="fa-solid fa-arrow-left"></i></kbd> <kbd><i class="fa-solid fa-arrow-right"></i></kbd> <kbd>Tab</kbd></p>
<Table TItem="DynamicObject" DynamicContext="DataTableKeyboardDynamicContext"
IsBordered="true" IsMultipleSelect="true" IsExcel="true" ShowExtendButtons="true">
</Table>
</DemoBlock>
<Tips class="mt-3">
<p>@((MarkupString)Localizer["P11"].Value)</p>
</Tips>
<p class="mt-3">@((MarkupString)Localizer["P12"].Value)</p>
<p>
<div class="code-label">@((MarkupString)Localizer["P13"].Value)</div>
<div class="mt-2">@((MarkupString)Localizer["P14"].Value)</div>
<div class="mt-2">@((MarkupString)Localizer["P15"].Value)</div>
</p>
<Pre>protected override void OnInitialized()
{
base.OnInitialized();
DataTableDynamicContext = new(UserData, (context, col) =>
{
// @Localizer["P16"]
if (col.GetFieldName() == nameof(Foo.Education))
{
col.ComponentType = typeof(Select<string>);
// @Localizer["P17"]
col.Items = typeof(EnumEducation).ToSelectList(new SelectedItem("", Localizer["NullItemText"].Value));
}
});
}</Pre>
<p>
<div class="code-label">@((MarkupString)Localizer["P18"].Value)</div>
<div class="mt-2">@((MarkupString)Localizer["P19"].Value)</div>
</p>
<Pre>protected override void OnInitialized()
{
DataTableDynamicContext.OnChanged = args =>
{
// @Localizer["P20"]
Trace.Log($"# valueS: {args.Items.Count()} - type: {args.ChangedType}");
return Task.CompletedTask;
};
}</Pre>
<p>
<div class="code-label">@((MarkupString)Localizer["P21"].Value)</div>
<div class="mt-2">@((MarkupString)Localizer["P22"].Value)</div>
</p>
<Pre>protected override void OnInitialized()
{
// @Localizer["P23"]
var method = DataTableDynamicContext.OnValueChanged;
DataTableDynamicContext.OnValueChanged = async (model, col, val) =>
{
// @Localizer["P24"]
if (method != null)
{
// @Localizer["P25"]
await method(model, col, val);
}
// @Localizer["P26"]
Trace.Log($"Change Notification: {col.GetFieldName()} - Value: {val?.ToString()}");
};
}</Pre>
// 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 System.Data;
namespace BootstrapBlazor.Shared.Samples.Table;
/// <summary>
///
/// </summary>
partial class TablesDynamicExcel
{
[NotNull]
private DataTableDynamicContext? DataTableDynamicContext { get; set; }
[NotNull]
private DataTableDynamicContext? DataTableKeyboardDynamicContext { get; set; }
private DataTable UserData { get; } = new DataTable();
private DataTable KeyboardData { get; } = new DataTable();
[Inject]
[NotNull]
private IStringLocalizer<Foo>? LocalizerFoo { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<TablesDynamicExcel>? Localizer { get; set; }
[Inject]
[NotNull]
private IStringLocalizer<Tables>? TablesLocalizer { get; set; }
private string? ButtonAddColumnText { get; set; }
private string? ButtonRemoveColumnText { get; set; }
[NotNull]
private BlockLogger? Trace { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
ButtonAddColumnText ??= TablesLocalizer[nameof(ButtonAddColumnText)];
ButtonRemoveColumnText ??= TablesLocalizer[nameof(ButtonRemoveColumnText)];
// 初始化 DataTable
InitDataTable();
// 初始化 DataTableContext 绑定 Table 组件
InitDataTableContext();
// 键盘支持示例
InitDataTableKeyboard();
}
private void InitDataTable()
{
UserData.Columns.Add(new DataColumn(nameof(Foo.DateTime), typeof(DateTime)) { DefaultValue = DateTime.Now });
UserData.Columns.Add(nameof(Foo.Name), typeof(string));
UserData.Columns.Add(nameof(Foo.Complete), typeof(bool));
UserData.Columns.Add(nameof(Foo.Education), typeof(string));
UserData.Columns.Add(nameof(Foo.Count), typeof(int));
Foo.GenerateFoo(LocalizerFoo, 10).ForEach(f =>
{
UserData.Rows.Add(f.DateTime, f.Name, f.Complete, f.Education, f.Count);
});
}
private void InitDataTableContext()
{
DataTableDynamicContext = new(UserData, (context, col) =>
{
// 设置 Enum 类型渲染成 Select
if (col.GetFieldName() == nameof(Foo.Education))
{
col.ComponentType = typeof(Select<string>);
col.Items = typeof(EnumEducation).ToSelectList(new SelectedItem("", LocalizerFoo["NullItemText"].Value));
}
if (col.GetFieldName() == nameof(Foo.Complete))
{
col.Align = Alignment.Center;
}
});
var method = DataTableDynamicContext.OnValueChanged;
DataTableDynamicContext.OnValueChanged = async (model, col, val) =>
{
// 调用内部提供的方法
if (method != null)
{
// 内部方法会更新原始数据源 DataTable
await method(model, col, val);
}
// 输出日志信息
Trace.Log($"单元格变化通知 列: {col.GetFieldName()} - 值: {val?.ToString()}");
};
DataTableDynamicContext.OnChanged = args =>
{
// 输出日志信息
Trace.Log($"集合值变化通知 行: {args.Items.Count()} - 类型: {args.ChangedType}");
return Task.CompletedTask;
};
}
private void InitDataTableKeyboard()
{
KeyboardData.Columns.Add("Column 1", typeof(string));
KeyboardData.Columns.Add("Column 2", typeof(string));
KeyboardData.Columns.Add("Column 3", typeof(string));
KeyboardData.Columns.Add("Column 4", typeof(string));
KeyboardData.Columns.Add("Column 5", typeof(string));
var index = 0;
Foo.GenerateFoo(LocalizerFoo, 9).ForEach(f =>
{
index++;
KeyboardData.Rows.Add($"Cell {index}1", $"Cell {index}2", $"Cell {index}3", $"Cell {index}4", $"Cell {index}5");
});
DataTableKeyboardDynamicContext = new(KeyboardData);
}
}