Как реализовать компонент DataGrid в серверной части Blazor? - PullRequest
0 голосов
/ 23 марта 2020

Я хочу создать компонент 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. Однако мне нужно что-то более сложное, потому что я хочу встроить функции сортировки, где вы можете щелкнуть заголовок столбца и сделать так, чтобы компонент сетки выполнил эту задачу за вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...