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.
Step 1: Create a Custom Column Class
Extend GridColumn and override the cell rendering behavior.
| Razor |
コードのコピー
|
|---|---|
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); } } |
|
Step 2: Add the Custom Column to the Grid
| Razor |
コードのコピー
|
|---|---|
<FlexGrid ItemsSource="customers" AutoGenerateColumns="false"> <FlexGridColumns> <GridColumn Binding="FirstName" /> <GridColumn Binding="LastName" /> <CustomColumn OnEditClicked="ShowEditPopup" /> </FlexGridColumns> </FlexGrid> |
|
Note: Accessing data through SelectedItem or SelectedIndex is supported, but it depends on the current grid selection state and is not recommended for reusable rendering scenarios.
Step 3: Handle the Click Event
Access the row data directly through row.DataItem.
| Razor |
コードのコピー
|
|---|---|
@code {
void ShowEditPopup(object dataItem)
{
var customer = dataItem as Customer;
// Process customer data
}
}
|
|
| Razor |
コードのコピー
|
|---|---|
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); } } |
|
Usage in the Page
| Razor |
コードのコピー
|
|---|---|
<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.
Step 1: Reuse the Custom Column
Reuse the existing CustomColumn implementation to maintain consistent row-level interaction behavior.
Step 2: Add a Loading Indicator Container
Wrap the FlexGrid inside a container that supports overlay rendering.
| Razor |
コードのコピー
|
|---|---|
<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> |
|
Step 3: Implement Loading State Logic
Introduce an IsLoading flag to control the loading overlay.
| Razor |
コードのコピー
|
|---|---|
@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.
Step 1: Add the Popup Window
| Razor |
コードのコピー
|
|---|---|
<FlexGrid ItemsSource="customers" AutoGenerateColumns="false"> <FlexGridColumns> <CustomColumn OnEditClicked="((d) => ShowEditPopup((Customer)d))" /> </FlexGridColumns> </FlexGrid> <C1Window @ref="window"> <PopupHeader>Data</PopupHeader> <PopupContent> Loading... </PopupContent> </C1Window> |
|
Step 2: Implement Asynchronous Processing
| Razor |
コードのコピー
|
|---|---|
@code {
C1Window window;
async Task ShowEditPopup(Customer data)
{
window.Open();
await Task.Delay(3000);
// Process data
window.Close();
}
}
|
|
Complete Code Example
| Razor |
コードのコピー
|
|---|---|
<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.
Display a toast notification after grid rendering or data loading using C1.Blazor.Input.C1Popup.
The following code example demonstrates the use of C1Popup:
| Razor |
コードのコピー
|
|---|---|
@using C1.Blazor.Grid
@using C1.Blazor.Input
@if (!_loadRequested)
{
<button @onclick="Load">load data</button>
}
else
{
<FlexGrid @ref="grid" ItemsSource="customers"
IsReadOnly="true"
AutoGenerateColumns="false"
SelectionMode="GridSelectionMode.Row"
Style="@("height:40vh")"
ColumnHeaderStyle="@("background-color:#eee;color:black;font-weight:bold;")">
<FlexGridColumns>
<GridColumn Binding="FirstName" Header="First Name" />
<GridColumn Binding="LastName" Header="Last Name" />
<GridColumn Binding="Address" Header="Address" />
<GridColumn Binding="City" Header="City" />
<GridColumn Binding="PostalCode" Header="Postal Code" />
<GridColumn Binding="Email" Header="Email" />
<CustomColumn OnEditClicked="((d) => ShowEditPopup((Customer)d))" />
</FlexGridColumns>
</FlexGrid>
}
<C1Popup @ref="popupLoading" IsDarkOverlay="true">
<PopupContent>
<div class="toast-content">
<span class="toast-icon">...</span>
<div class="toast-text">
<strong>Loading Data...</strong>
<p>Please Wait</p>
</div>
</div>
</PopupContent>
</C1Popup>
<C1Popup @ref="popupLoaded" IsDarkOverlay="true" IsDraggable="true">
<PopupContent>
<div class="toast-content">
<span class="toast-icon">?Elt;/span>
<div class="toast-text">
<strong>Data Loaded</strong>
<p>@customers?.Count records loaded successfully.</p>
</div>
</div>
</PopupContent>
</C1Popup>
@code {
FlexGrid grid;
ObservableCollection<Customer> customers;
List<string> info = new();
C1Popup popupLoading;
C1Popup popupLoaded;
bool _loadRequested;
bool _dataFinishedLoading;
async Task Load()
{
_loadRequested = true;
popupLoading.Open();
// emulates loading work
await Task.Delay(3000);
customers = new ObservableCollection<Customer>(Customer.Create(10000));
popupLoading.Close();
_dataFinishedLoading = true;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (_dataFinishedLoading)
{
_dataFinishedLoading = false;
popupLoaded.Open();
_ = AutoDismissToastAsync(5000);
}
}
async Task AutoDismissToastAsync(int delayMs)
{
await Task.Delay(delayMs);
popupLoaded.Close();
StateHasChanged();
}
}
|
|