Я хочу создать компонент DataGrid в Blazor, который можно использовать следующим образом на странице компонента Razor. Кто-то задавал тот же вопрос на трекере проблем Blazor GitHub по адресу https://github.com/dotnet/aspnetcore/issues/14886. Я попытался использовать код, который там указан, но обнаружил, что столбцы не добавляются в DataTable до тех пор, пока не запустится код сверху. В результате ни один из столбцов не отображается. Я думаю, что человек, который разместил пример кода, возможно, использовал клиентскую версию Blazor (WebAssembly). Это единственная причина, по которой я могу думать, что это будет работать для них, но не для меня.
Мой вопрос: каков рекомендуемый подход к созданию сложных компонентов пользовательского интерфейса в Blazor? Я думаю, что часть проблемы здесь в том, что DataTableColumn является компонентом. Тем не менее, он не предназначен для визуализации. Он просто используется в качестве данных конфигурации / параметров для DataTable, который выполняет фактический рендеринг. Итак, мне интересно, является ли это своего рода злоупотреблением дизайном Blazor. Telerik и другие компании делают это все же. https://demos.telerik.com/blazor-ui/grid/overview
Index.razor
@page "/users"
@using FolioLibrary
<fieldset>
<legend>Users</legend>
<DataTable Class="table" Data="@(folioContext.User2s.Take(10).Cast<dynamic>().ToList())">
<DataTableColumn Name="Id" Field="Id" Type="typeof(Guid)"></DataTableColumn>
<DataTableColumn Name="Name" Field="Name" Type="typeof(string)"></DataTableColumn>
<DataTableColumn>
<Template Context="item">
<a href="/@item.Id" class="btn">text</a>
</Template>
</DataTableColumn>
</DataTable>
@code
{
private FolioContext folioContext = new FolioContext();
}
DataTable.razor
<div class="col-12">
<CascadingValue Value="this">
<table class="@Class" id="@Id">
<thead>
<tr>
@ChildContent
</tr>
</thead>
<tbody>
@*@foreach (dynamic item in FilteredData.Skip((Page - 1) * PerPage).Take(PerPage))*@
@foreach (dynamic item in Data)
{
<tr>
@foreach (DataTableColumn column in Columns)
{
<td class="align-middle" width="@(column.Type == null ? "1%" : "")">
@if (column.Template is null)
{
@item.GetType().GetProperty(column.Field).GetValue(item, null)
}
else
{
@column.Template(item)
}
</td>
}
</tr>
}
</tbody>
</table>
</CascadingValue>
</div>
@code
{
[Parameter]
public string Class { get; set; }
[Parameter]
public string Id { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public List<dynamic> Data
{
get => data;
set
{
data = value;
FilteredData = data;
}
}
[Parameter]
public int PerPage { get; set; } = 25;
[Parameter]
public int Page { get; set; } = 1;
[Parameter]
public RenderFragment<dynamic> Actions { get; set; }
List<DataTableColumn> Columns { get; set; } = new List<DataTableColumn>();
List<dynamic> FilteredData { get; set; }
List<dynamic> data;
public void AddColumn(DataTableColumn column)
{
Columns.Add(column);
}
public void RemoveColumn(DataTableColumn column)
{
Columns.Remove(column);
}
}
DataTableColumn.razor
@implements IDisposable
<th>
<span>@Name</span>
</th>
@code
{
[Parameter]
public string Name { get; set; }
[Parameter]
public string Field { get; set; }
[Parameter]
public Type Type { get; set; }
[Parameter]
public RenderFragment<dynamic> Template { get; set; }
[CascadingParameter]
DataTable DataTable { get; set; }
protected override void OnInitialized()
{
DataTable.AddColumn(this);
}
public void Dispose()
{
DataTable.RemoveColumn(this);
}
}
Я временно добавил OnInitialized()
и OnAfterRender()
методы, чтобы увидеть, в каком порядке создаются компоненты, и когда возникают события, и следующим был порядок.
DataTable.OnInitialized
DataTableColumn.OnInitialized
DataTable.OnInitialized
DataTableColumn.OnInitialized
DataTable.OnAfterRender
DataTableColumn.OnAfterRender
Я думал, что мог бы используйте другое событие / метод, чтобы сделать его рендерингом позже, но циклы рендеринга кода / foreach находятся в основной части компонента Razor, а не в методе обратного вызова.
Прежде чем пытаться это сделать, у меня был более простой компонент сетки с HeaderTemplate и ItemTemplate. Однако мне нужно что-то более сложное, потому что я хочу встроить функции сортировки, где вы можете щелкнуть заголовок столбца и сделать так, чтобы компонент сетки выполнил эту задачу за вас.