[]
Custom columns provide programmatic control over cell rendering and direct access to the underlying row data through row.DataItem.
This approach is suitable for reusable rendering logic, event-driven interactions, and advanced rendering scenarios.
Extend GridColumn and override the cell rendering behavior.
public class CustomColumn : GridColumn
{
[Parameter]
public Action<object> OnEditClicked { get; set; }
protected override RenderFragment GetCellContentRenderFragment(
GridCellType cellType,
GridRow row)
{
if (cellType == GridCellType.Cell)
{
return new RenderFragment(builder =>
{
builder.OpenElement(0, "button");
builder.AddAttribute(
1,
"onclick",
EventCallback.Factory.Create<MouseEventArgs>(
this,
e => OnEditClicked?.Invoke(row.DataItem)));
builder.AddContent(2, "Info");
builder.CloseElement();
});
}
return base.GetCellContentRenderFragment(cellType, row);
}
}<FlexGrid ItemsSource="customers"
AutoGenerateColumns="false">
<FlexGridColumns>
<GridColumn Binding="FirstName" />
<GridColumn Binding="LastName" />
<CustomColumn OnEditClicked="ShowEditPopup" />
</FlexGridColumns>
</FlexGrid>Note: Accessing data through
SelectedItemorSelectedIndexis supported, but it depends on the current grid selection state and is not recommended for reusable rendering scenarios.
Access the row data directly through row.DataItem.
@code {
void ShowEditPopup(object dataItem)
{
var customer = dataItem as Customer;
// Process customer data
}
}public class CustomColumn : GridColumn
{
[Parameter]
public Action<object> OnEditClicked { get; set; }
protected override RenderFragment GetCellContentRenderFragment(
GridCellType cellType,
GridRow row)
{
if (cellType == GridCellType.Cell)
{
return new RenderFragment(builder =>
{
builder.OpenElement(0, "button");
builder.AddAttribute(1, "class", "btn btn-sm btn-primary");
builder.AddAttribute(
2,
"onclick",
EventCallback.Factory.Create<MouseEventArgs>(
this,
e => OnEditClicked?.Invoke(row.DataItem)));
builder.AddContent(3, "Info");
builder.CloseElement();
});
}
return base.GetCellContentRenderFragment(cellType, row);
}
}<FlexGrid ItemsSource="customers"
IsReadOnly="true"
AutoGenerateColumns="false">
<FlexGridColumns>
<GridColumn Binding="FirstName" Header="First Name" />
<GridColumn Binding="LastName" Header="Last Name" />
<CustomColumn OnEditClicked="ShowEditPopup" />
</FlexGridColumns>
</FlexGrid>
@code {
List<string> info = new();
void ShowEditPopup(object dataItem)
{
var customer = dataItem as Customer;
info.Add($"Customer: {customer.FirstName} {customer.LastName}");
}
}After completing these steps, FlexGrid displays standard data columns together with a custom button column generated through a GridColumn override.
Each button is associated directly with its corresponding row data through row.DataItem. When the button is clicked, the related Customer object is passed to the event handler.
Custom columns can be combined with loading indicators and popup windows to support asynchronous workflows and provide visual feedback during processing operations.
Reuse the existing CustomColumn implementation to maintain consistent row-level interaction behavior.
Wrap the FlexGrid inside a container that supports overlay rendering.
<div style="position:relative;">
<FlexGrid ItemsSource="customers"
AutoGenerateColumns="false">
<FlexGridColumns>
<GridColumn Binding="FirstName" />
<GridColumn Binding="LastName" />
<CustomColumn
OnEditClicked="((d) => ShowEditPopup((Customer)d))" />
</FlexGridColumns>
</FlexGrid>
@if (IsLoading)
{
<div style="
position:absolute;
left:50%;
top:50%;
transform:translate(-50%, -50%);
background-color:#5252DF;
border-radius:20px;
padding:12px;">
<p style="font-size:26px; color:white;">
Loading...
</p>
</div>
}
</div>Introduce an IsLoading flag to control the loading overlay.
@code {
bool IsLoading;
async Task ShowEditPopup(Customer data)
{
IsLoading = true;
StateHasChanged();
await Task.Delay(3000);
// Process customer data
IsLoading = false;
}
}After the operation completes, the loading overlay is removed and normal grid interaction resumes.
Note: The loading overlay temporarily covers the grid interface while processing is in progress. This behavior prevents additional user interaction during the operation.
C1Window can be used together with custom columns to display row-specific data or asynchronous processing results.
<FlexGrid ItemsSource="customers"
AutoGenerateColumns="false">
<FlexGridColumns>
<CustomColumn
OnEditClicked="((d) => ShowEditPopup((Customer)d))" />
</FlexGridColumns>
</FlexGrid>
<C1Window @ref="window">
<PopupHeader>Data</PopupHeader>
<PopupContent>
Loading...
</PopupContent>
</C1Window>@code {
C1Window window;
async Task ShowEditPopup(Customer data)
{
window.Open();
await Task.Delay(3000);
// Process data
window.Close();
}
}<FlexGrid ItemsSource="customers"
AutoGenerateColumns="false">
<FlexGridColumns>
<CustomColumn
OnEditClicked="((d) => ShowEditPopup((Customer)d))" />
</FlexGridColumns>
</FlexGrid>
<C1Window @ref="window">
<PopupHeader>Data</PopupHeader>
<PopupContent>
Loading...
</PopupContent>
</C1Window>
@code {
C1Window window;
async Task ShowEditPopup(Customer data)
{
window.Open();
await Task.Delay(3000);
// Process data
window.Close();
}
}After completing these steps, FlexGrid supports asynchronous row-level interaction through popup windows and loading indicators.
When a row action button is clicked, the application opens a popup window or displays a loading overlay while the operation is processed asynchronously.
As a result, the interface provides responsive user feedback during long-running operations without blocking the application workflow.