DataGrid: Features
Paging
Paging is handled automatically by theDataGrid
. You also have some additional attributes to configure paging based on your requirements.
ShowPager
to hide or show pagination controlsPageSize
the maximum number of items for each page.CurrentPage
current page number.PreviousPageButtonTemplate
template for previous page buttonNextPageButtonTemplate
template for next page buttonFirstPageButtonTemplate
template for first page buttonLastPageButtonTemplate
template for last page buttonPageButtonTemplate
template for explicated page button withPageButtonContext
as parameterPagerOptions
will provide you with additional settings to customize your pager.
Sorting
All columns can be sorted automatically if the option Sortable
is enabled on the column.
Use SortField
if you would like to set a different field or property to be considered by the sorting mechanism on a certain column.
Editing
The grid can perform some basic CRUD operations on the supplied Data
collection. To enable editing on data-grid, set the Editable
attribute to true on the DataGrid, and then set Editable
to true on each column you wish to be editable.
By default every time the Item
is saved it will be automatically handled by the data-grid itself. That means that all its fields will be populated after the user clicks on Save button. If you want to change that, you can just disable it by setting the UseInternalEditing
to false.
The grid can work in two different editing modes that can provide different user experiences.
EditMode
:
Form
editing is done in the internal DataGrid formInline
editing is done in the current rowPopup
editing is done in the the modal dialog
<Field> <FieldLabel> Edit Mode </FieldLabel> <FieldBody> <Select @bind-SelectedValue=""> <SelectItem Value="DataGridEditMode.Form">Form</SelectItem> <SelectItem Value="DataGridEditMode.Inline">Inline</SelectItem> <SelectItem Value="DataGridEditMode.Popup">Popup</SelectItem> </Select> </FieldBody> </Field> <DataGrid TItem="Employee" Data="" @bind-SelectedRow="" Editable Responsive ShowPager CommandMode="DataGridCommandMode.ButtonRow" EditMode="editMode"> <DataGridColumns> <DataGridCommandColumn NewCommandAllowed="false" EditCommandAllowed="false" DeleteCommandAllowed="false" > <SaveCommandTemplate> <Button ElementId="btnSave" Type="ButtonType.Submit" PreventDefaultOnSubmit Color="Color.Primary" Clicked="@context.Clicked">@context.LocalizationString</Button> </SaveCommandTemplate> <CancelCommandTemplate> <Button ElementId="btnCancel" Color="Color.Secondary" Clicked="@context.Clicked">@context.LocalizationString</Button> </CancelCommandTemplate> </DataGridCommandColumn> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGridColumns> <ButtonRowTemplate> <Button Color="Color.Success" Clicked="context.NewCommand.Clicked">New</Button> <Button Color="Color.Primary" Disabled="(selectedEmployee is null)" Clicked="context.EditCommand.Clicked">Edit</Button> <Button Color="Color.Danger" Disabled="(selectedEmployee is null)" Clicked="context.DeleteCommand.Clicked">Delete</Button> <Button Color="Color.Link" Clicked="context.ClearFilterCommand.Clicked">Clear Filter</Button> </ButtonRowTemplate> </DataGrid>
@code{ [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; private DataGridEditMode editMode = DataGridEditMode.Form; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
NewItemDefaultSetter
NewItemDefaultSetter
function is used to set default values when new item is created and before the edit form is shown. It will only be evaluate, if DataGrid
is editable.
<DataGrid TItem="Employee" Data="" @bind-SelectedRow="" NewItemDefaultSetter="" Editable Responsive ShowPager> <DataGridCommandColumn /> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGrid>
@code{ [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } void OnEmployeeNewItemDefaultSetter( Employee employee ) { employee.Salary = 100.0M; employee.IsActive = true; } }
Cascading values
In some case you want to update a different cell in a DataGrid when you update a value. This can be achieved with an UpdateCell
method. You have two ways of updating a cell:
- by calling
UpdateCell
on the context inside ofEditTemplate
, or - by calling
UpdateCellEditValue
on theDataGrid
instance
In the following example we’re simply calling context.UpdateCell
with a field-name to change and a new value that we want it to assign:
<DataGrid TItem="Employee" Data="" Editable EditMode="DataGridEditMode.Inline" Responsive ShowPager> <DataGridCommandColumn /> <DataGridColumn Field="@nameof( Employee.Salary )" Caption="Salary" Editable DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")"> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => { context.CellValue = v; context.UpdateCell( nameof( Employee.Tax ), v * context.Item.TaxPercentage ); })" /> </EditTemplate> </DataGridColumn> <DataGridColumn Field="@nameof( Employee.Tax )" Caption="Tax" Editable DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")"> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" Disabled /> </EditTemplate> </DataGridColumn> </DataGrid>
@code { [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
Filtering
Use an attribute Filterable
to enable or disable automatic filtering in grid component.
Default method for filtering is Contains
. If you want to change it you can set the FilterMethod
attribute on data grid. Supported methods are:
Contains
search for any occurrence (default)StartsWith
search only the beginningEndsWith
search only the endingEquals
search must match the entire valueNotEquals
opposite of Equals
<DataGrid TItem="Employee" Data="" Filterable FilterMethod="DataGridFilterMethod.StartsWith" Responsive> <DataGridColumn Field="@nameof( Employee.FirstName )" Caption="Name" Editable="false"></DataGridColumn> </DataGrid>
@code{ private List<Employee> employeeList = new() { new() { FirstName = "David" }, new() { FirstName = "Mladen" }, new() { FirstName = "John" }, new() { FirstName = "Ana" }, new() { FirstName = "Jessica" } }; }
Custom Filtering
Regular filter works on per field basis. To enable advanced search capabilities you can use an attributeCustomFilter
.
Filter API is fairly straightforward. All you need is to attach CustomFilter
to a function and bind search value to TextEdit
field. DataGrid will automatically respond to entered value.
Custom Filter: <TextEdit @bind-Text="" ></TextEdit> <DataGrid TItem="Employee" Data="" CustomFilter="" Responsive> <DataGridColumn Field="@nameof( Employee.FirstName )" Caption="Name" Editable="false"></DataGridColumn> </DataGrid>
@code{ private List<Employee> employeeList = new() { new() { FirstName = "David" }, new() { FirstName = "MLaden" }, new() { FirstName = "John" }, new() { FirstName = "Ana" }, new() { FirstName = "Jessica" } }; private string customFilterValue; private bool OnCustomFilter( Employee model ) { // We want to accept empty value as valid or otherwise // datagrid will not show anything. if ( string.IsNullOrEmpty( customFilterValue ) ) return true; return model.FirstName?.Contains( customFilterValue, StringComparison.OrdinalIgnoreCase ) == true; } }
Custom Column Filtering
Similar to the DataGrid custom filtering, it is also possible to use custom filtering on a per-column basis. You can define your editor with custom filtering to filter column values. You can see the dropdown menu to filter by gender in the following example by specifying<FilterTemplate>
on DataGridColumn
.
<DataGrid TItem="Employee" Data="" Filterable Responsive> <DataGridColumn Field="@nameof( Employee.FirstName )" Caption="Name" Editable="false"></DataGridColumn> <DataGridSelectColumn CustomFilter="" Field="@nameof( Employee.Gender )" Caption="Gender" Editable> <FilterTemplate> <Select TValue="string" SelectedValue="" SelectedValueChanged="@(value => { selectedGenderFilter = value; context.TriggerFilterChange( selectedGenderFilter ); })"> <SelectItem Value="@("*")">All</SelectItem> <SelectItem Value="@("M")">Male</SelectItem> <SelectItem Value="@("F")">Female</SelectItem> <SelectItem Value="@("D")">Diverse</SelectItem> </Select> </FilterTemplate> </DataGridSelectColumn> </DataGrid>
@code{ private List<Employee> employeeList = new() { new() { FirstName = "David", Gender = "M" }, new() { FirstName = "Mladen", Gender = "M" }, new() { FirstName = "John", Gender = "M" }, new() { FirstName = "Ana", Gender = "F" }, new() { FirstName = "Jessica", Gender = "F" } }; string selectedGenderFilter; private bool OnGenderCustomFilter( object itemValue, object searchValue ) { if ( searchValue is string genderFilter ) { return genderFilter == "*" || genderFilter == itemValue?.ToString(); } return true; } }
Resizable
<Field> <FieldLabel> Resize Mode </FieldLabel> <FieldBody> <Select @bind-SelectedValue=""> <SelectItem Value="TableResizeMode.Header">Header</SelectItem> <SelectItem Value="TableResizeMode.Columns">Columns</SelectItem> </Select> </FieldBody> </Field> <DataGrid TItem="Employee" Data="" @bind-SelectedRow="" Responsive Resizable ResizeMode=""> <DataGridCommandColumn /> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGrid>
@code { [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; private TableResizeMode resizeMode = TableResizeMode.Header; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
Fixed Header
<DataGrid TItem="Employee" Data="" @bind-SelectedRow="" Responsive PageSize="100" FixedHeader FixedHeaderDataGridMaxHeight="300px"> <DataGridCommandColumn /> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGrid>
@code { [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
Row Context Menu
You may need to know which element the user clicked in some cases so that you can use it in command handling. You might also want to change the menu's contents depending on which element the user clicked (e.g., disable or entirely remove some items from the menu based on a condition).
To integrate the context menu with the DataGrid, you need to:
-
Use the grid's
RowContextMenu
event to get the current row model and show the menu. -
Use the context menu's
MouseEventArgs
parameter to handle the desired operation.
In this example, the context menu is used to show the menu items, put an item in edit mode and delete items.
@using System.Drawing <DataGrid @ref="" TItem="Employee" Data="" @bind-SelectedRow="" RowContextMenu="" RowContextMenuPreventDefault="true" Responsive Editable> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> </DataGrid> @if ( showContextMenu ) { <Div Position="Position.Fixed" Background="Background.Danger" Style="@($"left:{contextMenuPos.X}px;top:{contextMenuPos.Y}px;")"> <ListGroup> <ListGroupItem Clicked="@(()=>OnContextItemEditClicked(contextMenuEmployee))"> <Icon Name="IconName.Edit" TextColor="TextColor.Secondary" /> Edit </ListGroupItem> <ListGroupItem Clicked="@(()=>OnContextItemDeleteClicked(contextMenuEmployee))"> <Icon Name="IconName.Delete" TextColor="TextColor.Danger" /> Delete </ListGroupItem> </ListGroup> </Div> }
@code { [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; private DataGrid<Employee> dataGridRef; bool showContextMenu = false; Employee contextMenuEmployee; Point contextMenuPos; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } protected Task OnRowContextMenu( DataGridRowMouseEventArgs<Employee> eventArgs ) { showContextMenu = true; contextMenuEmployee = eventArgs.Item; contextMenuPos = eventArgs.MouseEventArgs.Client; return Task.CompletedTask; } protected async Task OnContextItemEditClicked( Employee employee ) { await dataGridRef.Edit( employee ); showContextMenu = false; } protected async Task OnContextItemDeleteClicked( Employee employee ) { await dataGridRef.Delete( employee ); showContextMenu = false; } }
Scroll To
Scroll to API is available when theDataGrid
FixedHeader
or Virtualize
is set.
<Button Size="Size.Small" Color="Color.Primary" Clicked="">Scroll To Row</Button> <Button Size="Size.Small" Color="Color.Primary" Clicked="">Scroll To Pixels</Button> <DataGrid @ref="dataGridRef" TItem="Employee" Data="" @bind-SelectedRow="" Responsive ShowPager FixedHeader FixedHeaderDataGridMaxHeight="250px" PageSize="50"> <DataGridCommandColumn /> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGrid>
@code { [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; private DataGrid<Employee> dataGridRef; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } private Task ScrollToRow() => dataGridRef.ScrollToRow(30).AsTask(); private Task ScrollToPixels() => dataGridRef.ScrollToPixels(500).AsTask(); }