I have built a simple Grid component which mostly works, however I have run into a situation where I need to pass down the instance of GridRow being rendered to the GridCell to allow the GridCell component to access it's properties and modify if necessary.
The component is constructed from 3 parts, Grid, GridBody and GridCell as follows:
Usage in index.razor
<Grid Items="MyItems">
<GridBody Context="row">
<GridCell>@row.Id</GridCell>
<GridCell>@row.Item.Description</GridCell>
</GridBody>
</Grid>
Grid.razor:
@namespace Accounting.Web.Components
@typeparam TItem
@attribute [CascadingTypeParameter(nameof(TItem))];
<CascadingValue Value="this" IsFixed="true">
<table cellspacing="0">
<tbody>
@foreach (var row in Rows)
{
<tr>
@GridBody(row)
</tr>
}
</tbody>
</table>
</CascadingValue>
Grid.razor.cs
namespace Accounting.Web.Components
{
public class GridRow<TItem>
{
public TItem Item { get; set; } = default!;
public int Id { get; set; } = default!;
}
public partial class Grid<TItem>
{
[Parameter]
public RenderFragment<GridRow<TItem>> GridBody { get; set; } = default!;
[Parameter]
public IList<TItem> Items { get; set; } = default!;
}
}
GridBody.razor
@namespace Accounting.Web.Components
@typeparam GridRow
GridBody.razor.cs
using Microsoft.AspNetCore.Components;
namespace Accounting.Web.Components
{
public partial class GridBody<GridRow>
{
[Parameter]
public RenderFragment<GridRow> ChildContent { get; set; }
}
}
GridCell.razor
@namespace Accounting.Web.Components
@typeparam TItem
<td>
@ChildContent
</td>
GridCell.razor.cs
using Microsoft.AspNetCore.Components;
namespace Accounting.Web.Components
{
public partial class GridCell<TItem>
{
[CascadingParameter]
public Grid<TItem> Grid { get; set; } = default!;
[Parameter]
public int Id { get; set; } = default!;
[Parameter]
public GridRow<TItem> Row { get; set; } = default!;
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
}
}
In my various attempts I have attempted to pass down the row from GridBody to the GridCell but nothing has come close to working. The only way I can accomplish what I need is to directly pass row as a parameter in the tag in index.razor as follows:
<GridCell Row=row>@row.Id</GridCell>
This means I would ned to pass it in every GridCell. Is there a more elegant of passing the row down to the GridCell above without the use of a parameter?
The solution was straight forward, simply use a cascading value component to the Grid.razor:
Grid.razor:
GridCell.razor
GridCell.razor.cs