【发布时间】:2022-10-23 18:36:40
【问题描述】:
我正在尝试为 Blazor 客户端 SPA 创建表组件,该组件根据传递的项目实现行和列的动态显示。 到目前为止,我已经设法完成了行和列的显示。现在我希望实现排序,我将通过在标题列中设置一个排序按钮来实现。
到目前为止,我有 3 个组件:
DataTable 组件(父组件)
- DataTable 列组件(子组件)
- DataTable 排序组件(数据表组件的子级)
以下是代码的精简版本:
页面.razor
@page "/transactions/list"
@using Accounting.Web.Components.Grid;
@using Accounting.Web.Components.DataTable;
<h3>List</h3>
<DataTable Items="users">
<DataTableColumn TRowData="User" Expression="u => u.Id"/>
<DataTableColumn TRowData="User" Expression="u => u.Username" />
<DataTableColumn TRowData="User" Expression="u => u.DateOfBirth" />
<DataTableColumn TRowData="User"><div>Column B</div></DataTableColumn>
</DataTable>
@code {
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public DateTime DateOfBirth { get; set; }
}
public List<User> users { get; set; } = new (){
new User{
Id = 1,
Username = "Me",
DateOfBirth = new DateTime(1981, 12, 23)
},
new User{
Id = 2,
Username = "You",
DateOfBirth = new DateTime(1980, 1, 1)
}
};
}
数据表 Razor.razor
数据表呈现数据源中的每个列标题和行列
@typeparam TRowData <CascadingValue IsFixed="true" Value="this">@ChildContent</CascadingValue> (Items)
@* Render the table *@
<table>
<thead>
<tr>
@foreach (var column in columns)
{
@column.HeaderTemplate;
}
</tr>
</thead>
<tbody>
@{
if (Items != null)
{
var index = 0;
foreach (var item in Items)
{
@* Use @key to help the diff algorithm when updating the collection *@
<tr>
@foreach (var column in columns)
{
@column.CellTemplate(item);
}
</tr>
}
}
}
</tbody>
</table>
@code {
[Parameter]
public ICollection<TRowData> Items { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private readonly List<DataTableColumn<TRowData>> columns = new();
internal void AddColumn(DataTableColumn<TRowData> column)
{
columns.Add(column);
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
StateHasChanged();
}
}
}
数据表列.razor
@typeparam TRowData
@using System.Linq.Expressions
@code {
[CascadingParameter]
public DataTable<TRowData> Owner { get; set; }
[Parameter]
public string Title { get; set; }
[Parameter]
public bool Sortable { get; set; }
[Parameter]
public string Format { get; set; }
[Parameter]
public Expression<Func<TRowData, object>> Expression { get; set; }
[Parameter]
public RenderFragment<TRowData> ChildContent { get; set; }
private RenderFragment<TRowData> cellTemplate;
private RenderFragment headerTemplate;
private Func<TRowData, object> compiledExpression;
private Expression lastCompiledExpression;
public void test()
{
System.Console.WriteLine("test");
}
internal RenderFragment HeaderTemplate
{
get
{
return headerTemplate = (builder =>
{
var title = Title;
if (title == null && Expression != null)
{
title = GetMemberName(Expression);
}
builder.OpenElement(0, "th");
builder.AddContent(1, title);
if (Sortable)
{
builder.OpenComponent(0, typeof(DataTableSort));
builder.CloseComponent();
}
builder.CloseElement();
});
}
}
internal RenderFragment<TRowData> CellTemplate
{
get
{
return cellTemplate ??= (rowData => builder =>
{
builder.OpenElement(0, "td");
if (compiledExpression != null)
{
var value = compiledExpression(rowData);
var formattedValue = string.IsNullOrEmpty(Format) ? value?.ToString() : string.Format("{0:" + Format + "}", value);
builder.AddContent(1, formattedValue);
}
else
{
builder.AddContent(1, ChildContent, rowData);
}
builder.CloseElement();
});
}
}
protected override void OnInitialized()
{
Owner.AddColumn(this);
}
protected override void OnParametersSet()
{
if (lastCompiledExpression != Expression)
{
compiledExpression = Expression?.Compile();
lastCompiledExpression = Expression;
}
}
private static string GetMemberName<T>(Expression<T> expression)
{
return expression.Body switch
{
MemberExpression m => m.Member.Name,
UnaryExpression u when u.Operand is MemberExpression m => m.Member.Name,
_ => throw new NotSupportedException("Expression of type '" + expression.GetType().ToString() + "' is not supported")
};
}
}
上面的代码取自我正在使用的在线教程。
现在在 HeaderTemplate RenderFragment 方法中,您可以看到我正在渲染另一个组件:DataTableSort,请参见以下内容:
<button @onclick="onClicked">sort</button>
@code {
protected async Task onClicked()
{
System.Console.WriteLine("sort");
}
}
这就是我迷路的地方。我需要它,以便在按下按钮时,将一个事件传递给父 Datatable 列组件或 DataTable 祖父组件,我可以在其中根据单击的排序按钮对项目进行排序。
解决此问题的最佳方法是什么?
【问题讨论】: