I'm studying some paid grid components and they have a pretty cool "Bound Column" technique:
<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>
how can I achieve this? I want to create a very basic table:
<MyGrid DataSource=@MySource>
<MyColumn Field="Id" Name="My Id" />
</MyGrid>
to render:
<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>
It's not a trivial solution, you should to understand how Blazor works with components. Basically, the way, is to register children MyColumn
"templates" on outer MyGrid
component, then, render grid dynamically with a bit of reflection. Below I post the recipe ready for copy-paste, test and learn.
dotnet new blazorserver
Pages/MyColumn.razor
component:@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
}
}
Pages/MyGrid.razor
component:<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();
};
}
}
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With