Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,31 @@
</Table>
</DemoBlock>

<DemoBlock Title="@Localizer["BindComplexObjectTitle"]" Introduction="@Localizer["BindComplexObjectIntro"]" Name="BindComplexObject">
<section ignore>
<p>@((MarkupString)Localizer["BindComplexObjectP1"].Value)</p>
<p>@((MarkupString)Localizer["BindComplexObjectP2"].Value)</p>
<Button OnClick="@OnClickCompanyButton" Text="@Localizer["BindComplexObjectButtonText"]"></Button>
</section>
<Table TItem="ComplexFoo"
IsPagination="true" PageItemsSource="@PageItemsSource" CreateItemCallback="@CreateComplexFoo"
IsStriped="true" IsBordered="true"
ShowToolbar="false" IsMultipleSelect="true" ShowExtendButtons="false"
OnQueryAsync="@OnQueryComplexFooAsync">
<TableColumns>
<TableColumn @bind-Field="@context.DateTime" Text="@Localizer["ComplexFooDateTime"]" Width="120" FormatString="yyyy-MM-dd" />
<TableColumn @bind-Field="@context.Name" Text="@Localizer["ComplexFooName"]" Width="100" />
<TableColumn @bind-Field="@context.Address" Text="@Localizer["ComplexFooAddress"]" />
<TableColumn @bind-Field="@context.Age" Text="@Localizer["ComplexFooAge"]" />
<TableColumn @bind-Field="@context.Company" Text="@Localizer["ComplexFooCompany"]">
<Template Context="v">
<div>@v.Row.Company?.Name</div>
</Template>
</TableColumn>
</TableColumns>
</Table>
</DemoBlock>

<DemoBlock Title="@Localizer["OnColumnCreatingTitle"]" Introduction="@Localizer["OnColumnCreatingIntro"]" Name="OnColumnCreating">
<section ignore>
<Tips class="mb-3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public partial class TablesColumn
[NotNull]
private List<Foo>? Items { get; set; }

[NotNull]
private List<ComplexFoo>? ComplexItems { get; set; }

private static IEnumerable<int> PageItemsSource => new int[] { 5, 10, 20 };

private bool IgnoreColumn { get; set; }
Expand All @@ -30,6 +33,7 @@ protected override void OnInitialized()
base.OnInitialized();

Items = Foo.GenerateFoo(FooLocalizer);
ComplexItems = ComplexFoo.GenerateComplexFoo(FooLocalizer);
}

private void OnClickIgnoreColumn() => IgnoreColumn = !IgnoreColumn;
Expand All @@ -52,6 +56,10 @@ protected override void OnInitialized()
return Task.FromResult(ret);
}

/// <summary>
/// Foo 类型的异步查询
/// The async query of Items
/// </summary>
private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
{
IEnumerable<Foo> items = Items;
Expand Down Expand Up @@ -88,6 +96,46 @@ private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
});
}

/// <summary>
/// ComplexItems 的异步查询
/// The async query of ComplexItems
/// </summary>
private Task<QueryData<ComplexFoo>> OnQueryComplexFooAsync(QueryPageOptions options)
{
IEnumerable<ComplexFoo> items = ComplexItems;

// 先处理过滤再处理排序 提高性能
var isFiltered = false;
if (options.Filters.Count != 0)
{
items = items.Where(options.Filters.GetFilterFunc<ComplexFoo>());
isFiltered = true;
}

// 排序
var isSorted = false;
if (!string.IsNullOrEmpty(options.SortName))
{
items = items.Sort(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<ComplexFoo>()
{
Items = items,
TotalCount = total,
IsSorted = isSorted,
IsFiltered = isFiltered,
IsSearch = true
});
}

private static Task<bool> OnSaveAsync(Foo foo, ItemChangedType changedType) => Task.FromResult(true);

private static Task OnColumnCreating(List<ITableColumn> columns)
Expand Down Expand Up @@ -115,4 +163,93 @@ private void SetAlign(ITableColumn column, Alignment alignment)
_dateTimeAlign = alignment;
}
}

/// <summary>
/// 复杂类型 ComplexFoo 的构造回调
/// Construction callback of complex type ComplexFoo
/// </summary>
private ComplexFoo CreateComplexFoo() => ComplexFoo.Generate(FooLocalizer);

/// <summary>
/// 设置 ComplexItems 的 Company 属性
/// Set property Company of ComplexItems
/// </summary>
private Task OnClickCompanyButton()
{
foreach (var complexFoo in ComplexItems)
{
complexFoo.Company = new Company(((char)('A' + Random.Shared.Next(26))).ToString());
}
return Task.CompletedTask;
}

/// <summary>
/// 示例类 Company
/// Class sample Company
/// </summary>
private class Company(string name)
{
public string Name { get; set; } = name;
}

/// <summary>
/// 示例复杂类型 ComplexFoo
/// Complex class sample ComplexFoo
/// </summary>
private class ComplexFoo : Foo
{
public int Age { get; set; }

/// <summary>
/// 业务逻辑无法确保 Company 属性不为 null
/// The business logic cannot ensure that the Company property is not null.
/// </summary>
public Company? Company { get; set; }

/// <summary>
/// ComplexFoo 类不提供无参构造函数
/// Class ComplexFoo does not provide a parameterless constructor
/// </summary>
public ComplexFoo(int age)
{
Age = age;
}

/// <summary>
/// 生成含有随机数据的 ComplexFoo 实例
/// Generate an instance of ComplexFoo with random data
/// </summary>
public static new ComplexFoo Generate(IStringLocalizer<Foo> localizer) => new(Random.Shared.Next(20, 65))
{
Id = 1,
Name = localizer["Foo.Name", "1000"],
DateTime = System.DateTime.Now,
Address = localizer["Foo.Address", $"{Random.Shared.Next(1000, 2000)}"],
Count = Random.Shared.Next(1, 100),
Complete = Random.Shared.Next(1, 100) > 50,
Education = Random.Shared.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middle,
ReadonlyColumn = Random.Shared.Next(10, 50)
};

/// <summary>
/// 生成含有随机数据的 ComplexFoo 实例集合
/// Generate a list of ComplexFoo instances with random data
/// </summary>
/// <returns>
/// 返回一个含有随机数据的 ComplexFoo 实例集合
/// Return a List of ComplexFoo instances with random data
/// </returns>
public static List<ComplexFoo> GenerateComplexFoo(IStringLocalizer<Foo> localizer, int count = 80)
=> Enumerable.Range(1, count).Select(i => new ComplexFoo(Random.Shared.Next(20, 65))
{
Id = i,
Name = localizer["Foo.Name", $"{i:d4}"],
DateTime = System.DateTime.Now.AddDays(i - 1),
Address = localizer["Foo.Address", $"{Random.Shared.Next(1000, 2000)}"],
Count = Random.Shared.Next(1, 100),
Complete = Random.Shared.Next(1, 100) > 50,
Education = Random.Shared.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middle,
ReadonlyColumn = Random.Shared.Next(10, 50)
}).ToList();
}
}
10 changes: 10 additions & 0 deletions src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -5050,6 +5050,16 @@
"ShowCopyColumnDesc": "You can fine-tune the <code>Tooltip</code> related parameters of the copy column data icon by setting <code>ShowCopyColumnTooltip</code> <code>CopyColumnTooltipText</code> <code>CopyColumnCopiedTooltipText</code> and other settings",
"ShowColumnToolboxTitle": "Column Toolbox",
"ShowColumnToolboxIntro": "Enable the column toolbar button by setting the <code>ToolboxTemplate</code> parameter",
"BindComplexObjectTitle": "Bind Complex Types and Expressions",
"BindComplexObjectIntro": "When binding a complex type, whether the bound object collection is empty or not, the <code>TItem</code> must provide a parameterless constructor. Otherwise, it is required to provide a construction callback through <code>CreateItemCallback</code>. When binding a complex expression, the bound expression must not throw a <code>NullReferenceException</code> exception. If the business logic cannot avoid this issue, it is recommended to handle it using a <code>Template</code>",
"BindComplexObjectP1": "In this example, the complex type <code>ComplexFoo</code> does not have a parameterless constructor, so a construction callback for <code>ComplexFoo</code> should be provided through <code>CreateItemCallback</code>",
"BindComplexObjectP2": "In this example, we want to bind a complex expression <code>context.Company.Name</code> to the column <code>CompanyName</code>, but the business logic cannot ensure that the value of the <code>Company</code> property is not <code>null</code> at the time of binding. Therefore, we can first bind a simple expression and then handle it using the column template <code>Template</code>",
"BindComplexObjectButtonText": "Set company",
"ComplexFooDateTime": "DateTime",
"ComplexFooName": "Name",
"ComplexFooAddress": "Address",
"ComplexFooAge": "Age",
"ComplexFooCompany": "Company",
"OnColumnCreatingTitle": "Set current column properties",
"OnColumnCreatingIntro": "By specifying <code>OnColumnCreating</code> callback, make secondary data changes to the column collection",
"OnColumnCreatingP1": "Existing columns can be extended through the parameters in the <code>OnColumnCreating</code> callback method:",
Expand Down
10 changes: 10 additions & 0 deletions src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -5050,6 +5050,16 @@
"ShowCopyColumnDesc": "可以通过设置 <code>ShowCopyColumnTooltip</code> <code>CopyColumnTooltipText</code> <code>CopyColumnCopiedTooltipText</code> 等设置微调拷贝列数据图标的 <code>Tooltip</code> 相关参数",
"ShowColumnToolboxTitle": "列工具栏",
"ShowColumnToolboxIntro": "通过设置列 <code>ToolboxTemplate</code> 参数,开启列工具栏按钮",
"BindComplexObjectTitle": "绑定复杂类型和表达式",
"BindComplexObjectIntro": "当绑定复杂类型时,无论绑定的对象集合是否为空,都要求 <code>TItem</code> 提供无参构造函数,否则要求通过 <code>CreateItemCallback</code> 提供构造回调;当绑定复杂表达式时,要求绑定时该表达式不得引发 <code>NullReferenceException</code> 异常,如果业务逻辑无法避免此问题,建议使用 <code>Template</code> 进行处理",
"BindComplexObjectP1": "本例中,复杂类型 <code>ComplexFoo</code> 不具备无参构造函数,需通过 <code>CreateItemCallback</code> 提供 <code>ComplexFoo</code> 的构造回调",
"BindComplexObjectP2": "本例中,我们希望将复杂表达式 <code>context.Company.Name</code> 绑定到列 <code>CompanyName</code> 上,但是业务逻辑无法确保绑定时属性 <code>Company</code> 的值不为 <code>null</code> 。因此可以先绑定简单表达式,再通过列模板 <code>Template</code> 进行处理",
"BindComplexObjectButtonText": "设置公司",
"ComplexFooDateTime": "日期",
"ComplexFooName": "姓名",
"ComplexFooAddress": "地址",
"ComplexFooAge": "年龄",
"ComplexFooCompany": "公司",
"OnColumnCreatingTitle": "设置当前列属性",
"OnColumnCreatingIntro": "通过指定 <code>OnColumnCreating</code>回调,对列集合进行数据二次更改",
"OnColumnCreatingP1": "通过 <code>OnColumnCreating</code> 回调方法中的参数既可以对现有列进行扩展:",
Expand Down
Loading