I've created a generic TelerikGrid component that can handle any model is pass onto it. However, because of this, I cannot enable AutoGenerateColumns, since the model is not specified when the grid is being initialized. Instead, I have to manually define the columns using a variation of the example provided here: https://github.com/telerik/blazor-ui/blob/master/grid/binding-to-expando-object/BindingToExpandoObject/Pages/AutoGeneratedColumns.razor
@inject LocalStorageService _localStorage
@inject GenericHttpEntityService _entityService
@typeparam TItem
<div style="position: relative; width: 100%; min-height: 400px;">
<TelerikLoaderContainer OverlayThemeColor="light" Visible="@(!IsDoneLoading)"
Text="@null" Class="initial-data-loader">
<Template>
<TelerikLoader Type="LoaderType.Pulsing" Size="LoaderSize.Large"></TelerikLoader>
</Template>
</TelerikLoaderContainer>
<TelerikGrid Data="@GridData"
@ref="@Grid"
Height="460px"
RowHeight="60"
PageSize="10"
Pageable="true"
Sortable="true"
Resizable="true"
FilterMode="GridFilterMode.FilterMenu"
EditMode="GridEditMode.Popup"
OnRead="@ReadEntity"
OnStateInit="@((GridStateEventArgs<object> args) => OnStateInitHandler(args))"
OnStateChanged="@((GridStateEventArgs<object> args) => OnStateChangedHandler(args))">
<GridColumns>
@if (GridData != null && GridData.Any())
{
var firstItem = GridData.First();
var dictionary = firstItem.GetType().GetProperties().ToDictionary(prop => prop.Name, prop => prop.GetValue(firstItem, null));
foreach (var (key, value) in dictionary)
{
if (value == null)
{
continue;
}
<GridColumn Field="@key" FieldType="@value.GetType()"></GridColumn>
}
}
</GridColumns>
</TelerikGrid>
</div>
@code {
// Grid data
private List<object> GridData { get; set; } = new();
private int Total { get; set; }
// Loading
bool IsDoneLoading { get; set; }
// Grid state
TelerikGrid<object> Grid { get; set; }
string StorageKey { get; set; }
// Parameters
[Parameter]
public bool MaintainState { get; set; }
[Parameter]
public TItem Entity { get; set; }
protected override void OnInitialized()
{
StorageKey = $"{typeof(TItem).Name}GridState";
}
private async Task ReadEntity(GridReadEventArgs args)
{
var data = await _entityService.GetAll<TItem>(args.Request);
GridData = data.Records.Cast<object>().ToList();
Total = data.Total;
IsDoneLoading = true;
}
async Task OnStateInitHandler(GridStateEventArgs<object> args)
{
if (!MaintainState) return;
try
{
var state = await _localStorage.GetItem<GridState<object>>(StorageKey);
if (state != null)
{
args.GridState = state;
}
}
catch (InvalidOperationException)
{
// The JS Interop for the local storage cannot be used during pre-rendering
// so the code above will throw. Once the app initializes, it will work fine.
}
}
async void OnStateChangedHandler(GridStateEventArgs<object> args)
{
if (!MaintainState) return;
await _localStorage.SetItem(StorageKey, args.GridState);
}
}
The problem with this is that the visibility of the columns can't be defined in the model with annotations like [Display(AutoGenerated = false)]. Is there any way to do what I want to achieve here?