
Table Dynamic
Supports dynamically adding columns
Common usage
Only show DataTable
data
Demo
Loading...
@using System.Data;
@using BootstrapBlazor.Shared.Samples.Table;
@inject IStringLocalizer<Foo> Localizer
<div>
<Table TItem="DynamicObject" DynamicContext="DataTableDynamicContext" />
</div>
@code {
[NotNull]
private DataTableDynamicContext? DataTableDynamicContext { get; set; }
private DataTable UserData { get; } = new DataTable();
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
// 初始化 DataTable
InitDataTable();
// 初始化分页表格
InitPageDataTable();
}
private void CreateContext()
{
// 初始化动态类型上下文实例
DataTableDynamicContext = new DataTableDynamicContext(UserData, (context, col) =>
{
var propertyName = col.GetFieldName();
if (propertyName == nameof(Foo.DateTime))
{
context.AddRequiredAttribute(nameof(Foo.DateTime));
// 使用 AutoGenerateColumnAttribute 设置显示名称示例
context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), new KeyValuePair<string, object?>[]
{
new(nameof(AutoGenerateColumnAttribute.Text), Localizer[nameof(Foo.DateTime)].Value)
});
}
else if (propertyName == nameof(Foo.Name))
{
context.AddRequiredAttribute(nameof(Foo.Name), Localizer["Name.Required"]);
// 使用 Text 设置显示名称示例
col.Text = Localizer[nameof(Foo.Name)];
}
else if (propertyName == nameof(Foo.Count))
{
context.AddRequiredAttribute(nameof(Foo.Count));
// 使用 DisplayNameAttribute 设置显示名称示例
context.AddDisplayNameAttribute(nameof(Foo.Count), Localizer[nameof(Foo.Count)].Value);
}
else if (propertyName == nameof(Foo.Complete))
{
col.Filterable = true;
// 使用 DisplayAttribute 设置显示名称示例
context.AddDisplayAttribute(nameof(Foo.Complete), new KeyValuePair<string, object?>[]
{
new(nameof(DisplayAttribute.Name), Localizer[nameof(Foo.Complete)].Value)
});
}
else if (propertyName == nameof(Foo.Id))
{
col.Editable = false;
col.Visible = false;
}
})
{
OnDeleteAsync = items =>
{
// 数据源中移除
foreach (var item in items)
{
var id = item.GetValue(nameof(Foo.Id));
if (id != null)
{
var row = UserData.Rows.Find(id);
if (row != null)
{
UserData.Rows.Remove(row);
}
}
}
UserData.AcceptChanges();
return Task.FromResult(true);
},
OnChanged = args =>
{
if (args.ChangedType == DynamicItemChangedType.Add)
{
var item = args.Items.First();
item.SetValue(nameof(Foo.DateTime), DateTime.Today);
item.SetValue(nameof(Foo.Name), "新建值");
}
return Task.CompletedTask;
}
};
}
private void InitDataTable()
{
UserData.Columns.Add(nameof(Foo.Id), typeof(int));
UserData.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
UserData.Columns.Add(nameof(Foo.Name), typeof(string));
UserData.Columns.Add(nameof(Foo.Count), typeof(int));
UserData.PrimaryKey = new DataColumn[] { UserData.Columns[0] };
UserData.Columns[0].AutoIncrement = true;
Foo.GenerateFoo(Localizer, 10).ForEach(f =>
{
UserData.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
});
CreateContext();
}
private DataTable PageDataTable { get; set; } = new DataTable();
private int PageItems { get; set; }
private int TotalCount { get; set; }
private int PageIndex { get; set; } = 1;
private int PageCount { get; set; }
[NotNull]
private List<Foo>? PageFoos { get; set; }
private void InitPageDataTable()
{
PageDataTable.Columns.Add(nameof(Foo.Id), typeof(int));
PageDataTable.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
PageDataTable.Columns.Add(nameof(Foo.Name), typeof(string));
PageDataTable.Columns.Add(nameof(Foo.Count), typeof(int));
PageFoos = Foo.GenerateFoo(Localizer, 80);
TotalCount = PageFoos.Count;
PageIndex = 1;
PageItems = 2;
PageCount = (int)Math.Ceiling(TotalCount / 2.0);
RebuildPageDataTable();
}
private void RebuildPageDataTable()
{
PageDataTable.Rows.Clear();
// 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页
foreach (var f in PageFoos.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList())
{
PageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
}
PageDataTable.AcceptChanges();
}
}
Edit function
Add editing and maintenance functions
Demo
By setting the OnChanged
callback method of the DataTableDynamicContext
instance, the value is automatically set when a new row is created
Loading...
@using System.Data;
@using BootstrapBlazor.Shared.Samples.Table;
@inject IStringLocalizer<Foo> Localizer
<div>
<Table TItem="DynamicObject" DynamicContext="DataTableDynamicContext" ModelEqualityComparer="ModelEqualityComparer"
IsMultipleSelect="true" IsBordered="true" IsStriped="true" @bind-SelectedRows="SelectedItems"
ShowToolbar="true" ShowExtendButtons="true" />
<div class="mt-3">
@foreach (var item in SelectedItems)
{
<div>@item.GetValue(nameof(Foo.Name))</div>
}
</div>
</div>
@code {
[NotNull]
private DataTableDynamicContext? DataTableDynamicContext { get; set; }
private DataTable UserData { get; } = new DataTable();
private List<DynamicObject> SelectedItems { get; set; } = new List<DynamicObject>();
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
// 初始化 DataTable
InitDataTable();
// 初始化分页表格
InitPageDataTable();
}
private static bool ModelEqualityComparer(IDynamicObject x, IDynamicObject y) => x.GetValue("Id")?.ToString() == y.GetValue("Id")?.ToString();
private void CreateContext()
{
// 初始化动态类型上下文实例
DataTableDynamicContext = new DataTableDynamicContext(UserData, (context, col) =>
{
var propertyName = col.GetFieldName();
if (propertyName == nameof(Foo.DateTime))
{
context.AddRequiredAttribute(nameof(Foo.DateTime));
// 使用 AutoGenerateColumnAttribute 设置显示名称示例
context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), new KeyValuePair<string, object?>[]
{
new(nameof(AutoGenerateColumnAttribute.Text), Localizer[nameof(Foo.DateTime)].Value)
});
}
else if (propertyName == nameof(Foo.Name))
{
context.AddRequiredAttribute(nameof(Foo.Name), Localizer["Name.Required"]);
// 使用 Text 设置显示名称示例
col.Text = Localizer[nameof(Foo.Name)];
}
else if (propertyName == nameof(Foo.Count))
{
context.AddRequiredAttribute(nameof(Foo.Count));
// 使用 DisplayNameAttribute 设置显示名称示例
context.AddDisplayNameAttribute(nameof(Foo.Count), Localizer[nameof(Foo.Count)].Value);
}
else if (propertyName == nameof(Foo.Complete))
{
col.Filterable = true;
// 使用 DisplayAttribute 设置显示名称示例
context.AddDisplayAttribute(nameof(Foo.Complete), new KeyValuePair<string, object?>[]
{
new(nameof(DisplayAttribute.Name), Localizer[nameof(Foo.Complete)].Value)
});
}
else if (propertyName == nameof(Foo.Id))
{
col.Editable = false;
col.Visible = false;
}
})
{
OnDeleteAsync = items =>
{
// 数据源中移除
foreach (var item in items)
{
var id = item.GetValue(nameof(Foo.Id));
if (id != null)
{
var row = UserData.Rows.Find(id);
if (row != null)
{
UserData.Rows.Remove(row);
}
}
}
UserData.AcceptChanges();
return Task.FromResult(true);
},
OnChanged = args =>
{
if (args.ChangedType == DynamicItemChangedType.Add)
{
var item = args.Items.First();
item.SetValue(nameof(Foo.DateTime), DateTime.Today);
item.SetValue(nameof(Foo.Name), "新建值");
}
return Task.CompletedTask;
}
};
}
private void InitDataTable()
{
UserData.Columns.Add(nameof(Foo.Id), typeof(int));
UserData.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
UserData.Columns.Add(nameof(Foo.Name), typeof(string));
UserData.Columns.Add(nameof(Foo.Count), typeof(int));
UserData.PrimaryKey = new DataColumn[] { UserData.Columns[0] };
UserData.Columns[0].AutoIncrement = true;
Foo.GenerateFoo(Localizer, 10).ForEach(f =>
{
UserData.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
});
CreateContext();
}
private DataTable PageDataTable { get; set; } = new DataTable();
private int PageItems { get; set; }
private int TotalCount { get; set; }
private int PageIndex { get; set; } = 1;
private int PageCount { get; set; }
[NotNull]
private List<Foo>? PageFoos { get; set; }
private void InitPageDataTable()
{
PageDataTable.Columns.Add(nameof(Foo.Id), typeof(int));
PageDataTable.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
PageDataTable.Columns.Add(nameof(Foo.Name), typeof(string));
PageDataTable.Columns.Add(nameof(Foo.Count), typeof(int));
PageFoos = Foo.GenerateFoo(Localizer, 80);
TotalCount = PageFoos.Count;
PageIndex = 1;
PageItems = 2;
PageCount = (int)Math.Ceiling(TotalCount / 2.0);
RebuildPageDataTable();
}
private void RebuildPageDataTable()
{
PageDataTable.Rows.Clear();
// 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页
foreach (var f in PageFoos.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList())
{
PageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
}
PageDataTable.AcceptChanges();
}
}
Dynamic Column
Dynamic adjustment of the DataTable
table component automatically updates via code
Demo
Loading...
@using System.Data;
@using BootstrapBlazor.Shared.Samples.Table;
@inject IStringLocalizer<Foo> FooLocalizer
@inject IStringLocalizer<TablesDynamicDynamicCol> Localizer
<div>
<Table TItem="DynamicObject" DynamicContext="DataTableDynamicContext" ModelEqualityComparer="ModelEqualityComparer"
IsMultipleSelect="true" IsBordered="true" IsStriped="true"
ShowToolbar="true" ShowExtendButtons="true">
<TableToolbarTemplate>
<TableToolbarButton TItem="DynamicObject" Color="Color.Info" Icon="fa-fw fa-solid fa-circle-plus" Text="@ButtonAddColumnText" OnClick="OnAddColumn" />
<TableToolbarButton TItem="DynamicObject" Color="Color.Secondary" Icon="fa-fw fa-solid fa-circle-minus" Text="@ButtonRemoveColumnText" OnClick="OnRemoveColumn" />
</TableToolbarTemplate>
</Table>
</div>
@code {
[NotNull]
private DataTableDynamicContext? DataTableDynamicContext { get; set; }
private DataTable UserData { get; } = new DataTable();
private string? ButtonAddColumnText { get; set; }
private string? ButtonRemoveColumnText { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
ButtonAddColumnText ??= Localizer["TablesDynamicDynamicColButtonAddColumnText"];
ButtonRemoveColumnText ??= Localizer["TablesDynamicDynamicColButtonRemoveColumnText"];
// 初始化 DataTable
InitDataTable();
// 初始化分页表格
InitPageDataTable();
}
private static bool ModelEqualityComparer(IDynamicObject x, IDynamicObject y) => x.GetValue("Id")?.ToString() == y.GetValue("Id")?.ToString();
private void CreateContext()
{
// 初始化动态类型上下文实例
DataTableDynamicContext = new DataTableDynamicContext(UserData, (context, col) =>
{
var propertyName = col.GetFieldName();
if (propertyName == nameof(Foo.DateTime))
{
context.AddRequiredAttribute(nameof(Foo.DateTime));
// 使用 AutoGenerateColumnAttribute 设置显示名称示例
context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), new KeyValuePair<string, object?>[]
{
new(nameof(AutoGenerateColumnAttribute.Text), FooLocalizer[nameof(Foo.DateTime)].Value)
});
}
else if (propertyName == nameof(Foo.Name))
{
context.AddRequiredAttribute(nameof(Foo.Name), FooLocalizer["Name.Required"]);
// 使用 Text 设置显示名称示例
col.Text = FooLocalizer[nameof(Foo.Name)];
}
else if (propertyName == nameof(Foo.Count))
{
context.AddRequiredAttribute(nameof(Foo.Count));
// 使用 DisplayNameAttribute 设置显示名称示例
context.AddDisplayNameAttribute(nameof(Foo.Count), FooLocalizer[nameof(Foo.Count)].Value);
}
else if (propertyName == nameof(Foo.Complete))
{
col.Filterable = true;
// 使用 DisplayAttribute 设置显示名称示例
context.AddDisplayAttribute(nameof(Foo.Complete), new KeyValuePair<string, object?>[]
{
new(nameof(DisplayAttribute.Name), FooLocalizer[nameof(Foo.Complete)].Value)
});
}
else if (propertyName == nameof(Foo.Id))
{
col.Editable = false;
col.Visible = false;
}
})
{
OnDeleteAsync = items =>
{
// 数据源中移除
foreach (var item in items)
{
var id = item.GetValue(nameof(Foo.Id));
if (id != null)
{
var row = UserData.Rows.Find(id);
if (row != null)
{
UserData.Rows.Remove(row);
}
}
}
UserData.AcceptChanges();
return Task.FromResult(true);
},
OnChanged = args =>
{
if (args.ChangedType == DynamicItemChangedType.Add)
{
var item = args.Items.First();
item.SetValue(nameof(Foo.DateTime), DateTime.Today);
item.SetValue(nameof(Foo.Name), "新建值");
}
return Task.CompletedTask;
}
};
}
private void InitDataTable()
{
UserData.Columns.Add(nameof(Foo.Id), typeof(int));
UserData.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
UserData.Columns.Add(nameof(Foo.Name), typeof(string));
UserData.Columns.Add(nameof(Foo.Count), typeof(int));
UserData.PrimaryKey = new DataColumn[] { UserData.Columns[0] };
UserData.Columns[0].AutoIncrement = true;
Foo.GenerateFoo(FooLocalizer, 10).ForEach(f =>
{
UserData.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
});
CreateContext();
}
private Task OnAddColumn()
{
if (!UserData.Columns.Contains(nameof(Foo.Complete)))
{
UserData.Columns.Add(nameof(Foo.Complete), typeof(bool));
// 更新数据
var fs = Foo.GenerateFoo(FooLocalizer, 10);
for (var i = 0; i < fs.Count; i++)
{
UserData.Rows[i][nameof(Foo.Complete)] = fs[i].Complete;
}
CreateContext();
StateHasChanged();
}
return Task.CompletedTask;
}
private Task OnRemoveColumn()
{
if (UserData.Columns.Contains(nameof(Foo.Complete)))
{
UserData.Columns.Remove(nameof(Foo.Complete));
CreateContext();
StateHasChanged();
}
return Task.CompletedTask;
}
private DataTable PageDataTable { get; set; } = new DataTable();
private int PageItems { get; set; }
private int TotalCount { get; set; }
private int PageIndex { get; set; } = 1;
private int PageCount { get; set; }
[NotNull]
private List<Foo>? PageFoos { get; set; }
private void InitPageDataTable()
{
PageDataTable.Columns.Add(nameof(Foo.Id), typeof(int));
PageDataTable.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
PageDataTable.Columns.Add(nameof(Foo.Name), typeof(string));
PageDataTable.Columns.Add(nameof(Foo.Count), typeof(int));
PageFoos = Foo.GenerateFoo(FooLocalizer, 80);
TotalCount = PageFoos.Count;
PageIndex = 1;
PageItems = 2;
PageCount = (int)Math.Ceiling(TotalCount / 2.0);
RebuildPageDataTable();
}
private void RebuildPageDataTable()
{
PageDataTable.Rows.Clear();
// 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页
foreach (var f in PageFoos.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList())
{
PageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
}
PageDataTable.AcceptChanges();
}
}
Pagination
Use Pagination
component
Demo
Loading...
@using System.Data;
@using BootstrapBlazor.Shared.Samples.Table;
@inject IStringLocalizer<Foo> Localizer
<div>
<Table TItem="DynamicObject" DynamicContext="DataTablePageDynamicContext" />
<Pagination PageCount="@PageCount" PageIndex="@PageIndex" OnPageLinkClick="@OnPageLinkClick" class="mt-3" />
</div>
@code{
[NotNull]
private DataTableDynamicContext? DataTablePageDynamicContext { get; set; }
private DataTable UserData { get; } = new DataTable();
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
// 初始化 DataTable
InitDataTable();
// 初始化分页表格
InitPageDataTable();
}
private void InitDataTable()
{
UserData.Columns.Add(nameof(Foo.Id), typeof(int));
UserData.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
UserData.Columns.Add(nameof(Foo.Name), typeof(string));
UserData.Columns.Add(nameof(Foo.Count), typeof(int));
UserData.PrimaryKey = new DataColumn[]
{
UserData.Columns[0]
};
UserData.Columns[0].AutoIncrement = true;
Foo.GenerateFoo(Localizer, 10).ForEach(f =>
{
UserData.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
});
}
private DataTable PageDataTable { get; set; } = new DataTable();
private int PageItems { get; set; }
private int TotalCount { get; set; }
private int PageIndex { get; set; } = 1;
private int PageCount { get; set; }
[NotNull]
private List<Foo>? PageFoos { get; set; }
private void InitPageDataTable()
{
PageDataTable.Columns.Add(nameof(Foo.Id), typeof(int));
PageDataTable.Columns.Add(nameof(Foo.DateTime), typeof(DateTime));
PageDataTable.Columns.Add(nameof(Foo.Name), typeof(string));
PageDataTable.Columns.Add(nameof(Foo.Count), typeof(int));
PageFoos = Foo.GenerateFoo(Localizer, 80);
TotalCount = PageFoos.Count;
PageIndex = 1;
PageItems = 2;
PageCount = (int)Math.Ceiling(TotalCount / 2.0);
RebuildPageDataTable();
}
private void RebuildPageDataTable()
{
PageDataTable.Rows.Clear();
// 此处代码可以通过数据库获得分页后的数据转化成 DataTable 再给 DynamicContext 即可实现数据库分页
foreach (var f in PageFoos.Skip((PageIndex - 1) * PageItems).Take(PageItems).ToList())
{
PageDataTable.Rows.Add(f.Id, f.DateTime, f.Name, f.Count);
}
PageDataTable.AcceptChanges();
DataTablePageDynamicContext = new DataTableDynamicContext(PageDataTable, (context, col) =>
{
var propertyName = col.GetFieldName();
if (propertyName == nameof(Foo.DateTime))
{
context.AddRequiredAttribute(nameof(Foo.DateTime));
// 使用 AutoGenerateColumnAttribute 设置显示名称示例
context.AddAutoGenerateColumnAttribute(nameof(Foo.DateTime), new KeyValuePair<string, object?>[] { new(nameof(AutoGenerateColumnAttribute.Text), Localizer[nameof(Foo.DateTime)].Value) });
}
else if (propertyName == nameof(Foo.Name))
{
context.AddRequiredAttribute(nameof(Foo.Name), Localizer["Name.Required"]);
// 使用 Text 设置显示名称示例
col.Text = Localizer[nameof(Foo.Name)];
}
else if (propertyName == nameof(Foo.Count))
{
context.AddRequiredAttribute(nameof(Foo.Count));
// 使用 DisplayNameAttribute 设置显示名称示例
context.AddDisplayNameAttribute(nameof(Foo.Count), Localizer[nameof(Foo.Count)].Value);
}
else if (propertyName == nameof(Foo.Id))
{
col.Editable = false;
col.Visible = false;
}
});
}
/// <summary>
/// 点击页码处理函数
/// </summary>
/// <param name = "pageIndex"></param>
/// <returns></returns>
private Task OnPageLinkClick(int pageIndex)
{
PageIndex = pageIndex;
RebuildPageDataTable();
StateHasChanged();
return Task.CompletedTask;
}
}
B station related video link
交流群