Столбец сетки Blazor, привязанный по имени поля

Я изучаю некоторые платные компоненты сетки, и у них есть довольно крутая техника "Bound Column":

<TelerikGrid Data=@GridData>
    <GridColumns>
        <GridColumn Field="TemperatureC" Title="Temp. C" />
        <GridColumn Field="Summary" />
    </GridColumns>
    <GridToolBar>
        <GridCommandButton Command="Add" Icon="add">Add Forecast</GridCommandButton>
    </GridToolBar>
</TelerikGrid>

<DxDataGrid Data="@DataSource">
    <DxDataGridColumn Field="@nameof(ProductFlat.Id)">
    </DxDataGridColumn>
    <DxDataGridColumn Field="@nameof(ProductFlat.Category)">
    </DxDataGridColumn>
</DxDataGrid>

как я могу этого добиться? Я хочу создать очень простую таблицу:

<MyGrid DataSource=@MySource>
  <MyColumn Field="Id" Name="My Id" />
</MyGrid>

визуализировать:

<table class="table">
  <thead>
    <tr>
      <th scope="col">My Id</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>#1</td>
    </tr>
    <tr>
      <td>#2</td>
    </tr>
  </tbody>
</table>

person Alexandre    schedule 09.12.2019    source источник
comment
Подсказка: используйте отражение   -  person agua from mars    schedule 10.12.2019
comment
@aguafrommars, да, это смесь методов Reflection, CascadingValue, Lifecycle и динамических RenderFragments :)   -  person dani herrera    schedule 10.12.2019
comment
@daniherrera Мне было лень предоставить полное решение: D   -  person agua from mars    schedule 10.12.2019
comment
@aguafrommars, Да, я тоже несколько ждал ответа ... но это было интересное упражнение.   -  person dani herrera    schedule 10.12.2019
comment
Конечно, размышления - это лучший способ, но! Как перепроектировать дочерний контент в массив MyColumn? Он нужен мне для создания заголовка сетки   -  person Alexandre    schedule 10.12.2019
comment
@Alexandre, обратный инжиниринг не требуется, просто сообщите о существовании дочернего элемента внешнему компоненту, отправляющему родительский элемент через CascadingValue. Было забавным испытанием. Полный код моего ответа.   -  person dani herrera    schedule 10.12.2019


Ответы (1)


Это нетривиальное решение, вы должны понимать, как Blazor работает с компонентами. По сути, способ состоит в том, чтобы зарегистрировать дочерние MyColumn "шаблоны" во внешнем MyGrid компоненте, а затем динамически визуализировать сетку с небольшим отражением. Ниже я публикую рецепт, готовый к копипасту, тестированию и изучению.

Шаг 0: Создайте шаблонную демонстрацию Blazor:

dotnet new blazorserver

Шаг 1. Создайте Pages/MyColumn.razor компонент:

@code {
    [Parameter]
    public string Field { get; set; }

    [CascadingParameter]
    private MyGrid Parent { get; set; }    

    protected override void OnInitialized()
    {
        base.OnInitialized();        
        Parent.AddColumn(this); //register child into parent
    }
}

Шаг 2: Создайте Pages/MyGrid.razor компонент:

<CascadingValue Value="this">
<table class="table">
    <tbody>
        @ChildContent
        @foreach (var item in DataSource)
        {
            @RowItem(item) 
        }
    </tbody>
</table>
</CascadingValue>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public IEnumerable<object> DataSource { get; set; }

    List<MyColumn> Columns = new List<MyColumn>();
    public void AddColumn(MyColumn column)
    {
        Columns.Add(column);
        StateHasChanged();
    }

// Here the function to create each row dynamically:

    private RenderFragment RowItem(object row)
    {   
        int i = 0;
        return b =>          // create dynamically
        {
            b.OpenElement(++i, "tr");
            foreach(var column in Columns)
            {
                b.OpenElement(++i, "td");
                var val = row.GetType().GetProperty(column.Field)
                          .GetValue(row, null).ToString();                
                b.AddContent(++i,val);
                b.CloseElement();
            }
            b.CloseElement();
        };
    }
}

Шаг 3. Используйте свою сетку на Pages/FetchData.razor

@page "/fetchdata"

@using s.Data
@inject WeatherForecastService ForecastService

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from a service.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <MyGrid DataSource=@forecasts>
       <MyColumn Field="Date"/>
       <MyColumn Field="Summary"/>
    </MyGrid>
}

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
}

Результат:

введите описание изображения здесь

person dani herrera    schedule 09.12.2019
comment
Молодец! Дополнительная информация: Создание шаблонных компонентов Blazor blazorhelpwebsite.com / Blog / tabid / 61 / EntryId / 4339 / - person Michael Washington; 10.12.2019
comment
Я пытаюсь реализовать эту привязку, и мне было интересно, как я могу передать в нее данные из SignalR Hub? Предположим, у меня есть цены на акции, объем которых меняется каждую секунду. Я хочу, чтобы все пользователи (несколько окон браузера) видели одни и те же данные. - person Gray_Rhino; 25.11.2020