I am using MudBlazor's MudDataGrid, which functions very similarly to Blazor's QuickGrid. The grid's contents are determined by a RenderFragment parameter called Columns, which contains a list of mostly expression-tree-based property lookups:
<MudDataGrid Items="Widgets"><Columns><PropertyColumn Property="@(e => e.Id)" Title="Widget ID" Sortable="true"/><PropertyColumn Property="@(e => e.Type)" Title="Widget Type" Sortable="true"/><PropertyColumn Property="@(e => e.SubmittedOn)" Title="Submitted On" Sortable="true"/><PropertyColumn Property="@(e => e.SubmittedBy.UserName)" Title="Submitted By" Sortable="true" /><PropertyColumn Property="@(e => e.Description)" Title="Description" /><TemplateColumn Title="Actions"><CellTemplate><MudButton OnClick="@(() => NavigationManager.NavigateTo('Review/'+ context.Item.Id)">Review</MudButton></CellTemplate></TemplateColumn></Columns></DataGrid>@code { [Parameter] public List<Widget> Widgets { get; set;}}Under the hood, MudDataGrid is actually a generic class MudDataGrid<T>. Its parameter Items is of type IEnumerable<T>, so the object can automatically infer what T is based on what I pass in (in this case T=Widget). This is good.
However, now I want to create a wrapper for all my MudDataGrids introducing consistent styling and configuration. Call it CustomDataGrid.
@typeparam T<MudDataGrid T="T" Items="Items" Columns="Columns" ... (more attributes here for custom config)><ToolBarContent> @* Custom config stuff *@</ToolBarContent><PagerContent> @* Custom config stuff *@</PagerContent></MudDataGrid>@code { [Parameter] public IEnumerable<T>? Items { get; set; } [Parameter] public RenderFragment Columns { get; set; } // ...}Now let's use it back in our original widget-displaying component:
<CustomDataGrid Items="Widgets"><Columns><PropertyColumn Property="@(e => e.Id)" Title="Widget ID" Sortable="true"/><PropertyColumn Property="@(e => e.Type)" Title="Widget Type" Sortable="true"/><PropertyColumn Property="@(e => e.SubmittedOn)" Title="Submitted On" Sortable="true"/><PropertyColumn Property="@(e => e.SubmittedBy.UserName)" Title="Submitted By" Sortable="true" /><PropertyColumn Property="@(e => e.Description)" Title="Description" /><TemplateColumn Title="Actions"><CellTemplate><MudButton OnClick="@(() => NavigationManager.NavigateTo('Review/'+ context.Item.Id)">Review</MudButton></CellTemplate></TemplateColumn></Columns></DataGrid>@code { [Parameter] public List<Widget> Widgets { get; set;}}This raises a compile-time exception for each column, saying that it cannot infer the type parameters:
Components_Pages_WidgetDisplay_razor.g.cs(743,98): Error CS0411 : The type arguments for method 'TypeInference.CreatePropertyColumn_4<T, TProperty>(RenderTreeBuilder, int, int, Expression<Func<T, TProperty>>, int, string, int, bool?)' cannot be inferred from the usage. Try specifying the type arguments explicitly.The way to fix this is to manually specify both T and TProperty on each and every column in the table:
<CustomDataGrid Items="Widgets"><Columns><PropertyColumn T="Widget" TProperty="int" Property="@(e => e.Id)" Title="Widget ID" Sortable="true"/><PropertyColumn T="Widget" TProperty="WidgetType" Property="@(e => e.Type)" Title="Widget Type" Sortable="true"/><PropertyColumn T="Widget" TProperty="DateTime" Property="@(e => e.SubmittedOn)" Title="Submitted On" Sortable="true"/><PropertyColumn T="Widget" TProperty="string" Property="@(e => e.SubmittedBy.UserName)" Title="Submitted By" Sortable="true" /><PropertyColumn T="Widget" TProperty="string" Property="@(e => e.Description)" Title="Description" /><TemplateColumn T="Widget" Title="Actions"><CellTemplate><MudButton OnClick="@(() => NavigationManager.NavigateTo('Review/'+ context.Item.Id)">Review</MudButton></CellTemplate></TemplateColumn></Columns></DataGrid>@code { [Parameter] public List<Widget> Widgets { get; set;}}This is annoying, and I don't want to have to lose out on the type-inference features of Razor just by creating a wrapper component.
Is there any way to set up CustomDataGrid so it can infer the type variables of its columns?