Data Grid
Data grid shows a list of entity records. Also lets users sort, filter, and invoke commands or batch commands on the entity records.
Add a Data grid to a page view. Click on the element to open it's configuration:
General
Data
- Entity – first, pick an entity to list it's records
- Data source – by default lists all records of selected entity. This field allows to narrow the results with queries similar to this:
(model, db, ctx) => db.EntitySet.Where(e => e.Owner == ctx.User), wheremodelis the model of the page the grid sits on
General
- Label – Title of the Data grid
- Visible expression – security condition for showing the Data grid
- Display mode – option to switch to compact mode that has less UI elements around the grid. Normal mode lets application users export Data grid content as .XLS file
- Rows per grid page – rule for pagination of the Data grid
Responsivity
- Responsive behavior – what happens on a small screen: nothing, or the columns that do not fit move into a dropdown or a panel under the row
- Always visible first columns / Always visible last columns (IDE) – how many columns at the start and at the end of the grid stay in the row; everything in between moves into the overflow. Actions columns count as columns, so keeping the buttons at the end of the row is last columns = 1. At least one of the two counts must be 1 or more: with both at 0 the first column stays in the row anyway
- Always visible columns and Commands column always visible (Administration) – the same for a grid whose buttons sit in the single Actions column at the end; Commands column always visible keeps that column in the row
Columns
Create or edit Data grid columns in this section. Magic wand "wizard" helps you create columns for entity attributes and references.
Adding a new column
- Label – label of a Data grid column
- Type – data type of a column content
- Text expression – expression representing a text value shown in a column
- Custom sort expression – expression used for sorting the column values
- Text alignment – alignment of text within a column
Special column types
- Entity detail column – content of a column links to an entity detail page
- Entity – type of an referenced entity
- Entity expression – expression representing the entity value
- Display expression – expression representing the text displayed in a column
- Detail page – detail page used to display the entity
- Detail format – select Modal or normal format of the detail page
- Document download column – lets application users download documents
- Document expression – expression representing the document value
- Document display text expression – expression representing the text displayed in a column
Image preview column
It is also possible to create a column with images. The best practice is to first create previews of the images we want to display in this column so that they are not too large. The expression should then look something like this:
(entity, model, db, ctx) => entity.Preview != null ? $"})" : ""
Or like this if you want the preview to be a link to the original image:
(entity, model, db, ctx) => entity.Preview != null ? $"[})]({App.Urls.Documents.Generate(entity.Image)}){{target=\"_blank\"}}" : ""
Column expressions
Every column expression that is evaluated for a row - text, number, entity, document and custom sort expressions, and the number and entity display expressions - takes four arguments:
(row, model, db, ctx) => ...
row– the record the grid row showsmodel– the model of the page the grid sits on: the page's entity on a Detail page, the view's own model in a view, an empty model on a List pagedb,ctx– the app database and the business context, as in any other expression
Existing applications were converted by the platform (see 2026-09: One kind of command): a column expression that took the row alone, item => item.Name, now reads (item, model, db, ctx) => item.Name.
The names are up to you; only the order matters. For example, a column that shows how an order compares with the customer on whose Detail page the grid sits:
(order, customer, db, ctx) => order.Total > customer.CreditLimit ? "Over limit" : ""
Two expressions take something else, because they do not run for a row:
- Document display text expression –
(document) => ..., the document to be downloaded, e.g.(document) => document.FileName - Optional summary display expression –
(value) => ..., the computed sum or average, always as adecimal— also for the sum of an integer column — e.g.(value) => value.ToString("N0") + " pcs"
Highlights
Lets you create conditional highlights for Data grid rows. Merging highlights is possible and highlights lower in the list are evaluated later. For example conditions for two highlights are returned true for a specific row. Both highlights set shading color and only the first highlight sets an icon. The row will get icon from the first highlight and shading from the second highlight.
- Name – name of the highlight. Shows in a list of highlights and in a Legend of a Data grid
- Icon – icon that will show next to a Data grid row
- Color shading – background and text colors of a Data grid row
- Use bold text – "false" will not override "true" when merging highlights
- Use italic text – "false" will not override "true" when merging highlights
- Highlight condition –
(row, model, db, ctx) => bool, with the same arguments as a column expression; the highlight is used for the rows it returns true for
Filters
Lets you create filters for application users to further narrow down the content of a Data grid. Magic wand "wizard" helps you create filters for attributes and references of the entity.
- Name – name of the filter, shows in a filter layout
- Data type – data type of filtered value
- Constraint – type of constraint used when comparing filter value with data source.Constraints are mostly self explanatory, except for date range filters:
- Inside range – returns true when entity value is inside range of the filter value
- Contains range – returns true when filter value is inside range of the entity value
MyEntity.MyDate.HasValue ? DateRange.OfDay(MyEntity.MyDate) : DateRange.OfDay(DateTime.MinValue) - Filtered expression – expression representing the value on which the filter is applied
Do not forget to add created filters to a layout.
Filters layout
Created filters need to be added to layout to be accessible to application users. Select a Layout type and then add desired filters from the Data fields menu.
Clicking a data field in layout opens it's preferences where you can set up default values, just like when editing any other view.
Having default values in the filters mean that whenever app user opens the page, filter expand is opened and data is filtered.
Commands
Row commands are the buttons of a grid row. They live in an Actions column:
- In the Administration, adding at least one command to a Data grid creates one Actions column at the end of the grid, and all commands have their buttons there.
- In the IDE, Actions is a column type of its own. Add an Actions column where the buttons should be, and add the commands to it. A grid can have any number of Actions columns, each anywhere in the column order. The column's Label is optional - without one the header stays empty and reads "Actions" to screen readers. An Actions column has no expressions and is never sortable (as the default sort column it is ignored); a highlight can apply to it like to any other column, and a grid needs at least one column that is not an Actions column.
App users can hide an Actions column in the grid's column settings, like any other column.
Magic wand "wizard" helps create common commands (like system command "Delete entity") or Business commands whose model can take a row of the grid.
- Type of command – Business or System command
- Command – select a command to be executed
- Execution mode – Execute command runs the command with the mapped values; Open command window opens the command's page with them prefilled for the app user to submit. See Execution mode
- Before executing (Invoke mode in the IDE) – what happens to the page before the command runs: Execute without validating (the default), Validate only, or Validate and save the page. See Unsaved changes on the page
- Parameters – map values into the command's model with expressions
(row, model, db, ctx) => ..., whererowis the grid row andmodelthe entity of the page the grid sits on.(row, model, db, ctx) => rowhands the row itself;(row, model, db, ctx) => modelhands the page's entity, e.g. the parent of a child row - Label – text label of a command button
- Icon – icon of a command button
- Enabled condition –
(row, model, db, ctx) => bool, determining if the command is enabled for a row - Visible condition –
(row, model, db, ctx) => bool, determining if the command is visible for a row
Batch commands
Adding at least one Batch command to a Data grid creates a Batch commands expand above and checkbox column on the left side of the Data grid.
Creating a Batch command is the same as creating a Command, but the command receives the selection: its model declares an Entity Collection reference to the grid's entity, and the parameter expressions take the selection instead of a row - (selection, model, db, ctx) => selection, where selection is the selected records as an ICollection<T> backed by a query (see Passing the selection to a batch command).
The command is invoked once for the whole selection. Its two conditions have different signatures:
- Enabled condition –
(row, model, db, ctx) => bool, evaluated per row. Only the selected rows for which it returns true are handed to the command. - Visible condition –
(model, db, ctx) => bool, wheremodelis the entity of the page the grid sits on. It decides whether the command's button is shown at all, before any row is selected, so it takes no row and no selection. It is re-evaluated when the page's model changes, e.g.(model, db, ctx) => model.State == OrderState.Open.
To act on what the user selected, use the Parameters (selection) or the command's own body, not the Visible condition.
What the selection contains
selection is not just the ticked checkboxes. It is the grid's Data source, narrowed by the filters the user has set, then by the selected rows ("select all" selects every filtered row, including rows on other pages, minus the ones unticked), then by the Enabled condition. If nothing is left, the command does not start and the user gets an error.
The selection is cleared once the command is accepted, in both execution modes.
Execution mode
Every command and batch command has an Execution mode.
Execute command
The parameter mapping is evaluated, the command's model is built from it and the command is run straight away. The app user sees the command's progress window; the grid does not wait for the command and refreshes when it finishes.
Open command window
The parameter mapping is evaluated, but nothing runs yet. The command's own window opens with the mapped values prefilled, and the app user reviews or completes them and submits the window, which runs the command. Use it when the user has to enter something the grid cannot provide, e.g. a note or a date for all selected records.
The mapping is only a prefill here. Map what the grid knows (the row, the selection, the page's entity) and leave the rest for the user; a value that evaluates to null is not prefilled and the window's model keeps its default.
The values reach the window as URL parameters named after the command model's members, so each mapped value is converted:
| Mapped value | Travels as |
|---|---|
an entity (row, model, a reference) | its id |
| a collection of entities | their ids |
selection, selection.Query() or any other IQueryable | a short key, see below |
| anything else | the value as text |
Unsaved changes on the page
A grid on an entity detail page sits next to the page's form, and the user may have edited the form without saving
it. The parameter mapping of a grid command sees those edits (model.Name is what the user typed), but the page's
entity itself - (row, model, db, ctx) => model - travels to the command as its id, and the command reads it from
the database: without the edits.
Before executing decides what the grid does with the page first, the same way as on an action button:
- Execute without validating – the command runs straight away. The page's unsaved edits stay in the form and do not reach the command. The default, and what every grid command did before the option existed.
- Validate only – the page is validated first; an invalid page stops the command. Nothing is saved.
- Validate and save the page – the page is validated and its pending edits are saved through the page's own save, and only once that succeeded the command runs, or its window opens. Use it when the command takes the page's entity and has to see what the user just edited. It only saves on an entity detail page; anywhere else the page has no save of its own and the option behaves as Validate only.
Passing the selection to a batch command
A batch command receives the selection through an Entity Collection reference in its model, mapped with (selection, model, db, ctx) => selection. The collection holds the selection's query and reads nothing until the command body reads it:
(model, db, ctx) =>
{
// In the database, however large the selection is:
var count = model.Selection.Count;
var total = model.Selection.Query().Sum(o => o.Price);
// A batch at a time:
foreach (var order in model.Selection.Query().BatchWithDefaultOrder(100))
order.Closed = true;
}
Enumerating the collection itself - foreach (var order in model.Selection), .ToList(), or LINQ operators called directly on it - loads the selected records into memory, and at most 1000 of them: a larger selection fails with EntityCollectionLimitExceededException. For a selection that can be large, use .Query(); see Entity collection limit.
The mapping may narrow the selection before handing it over. (selection, model, db, ctx) => selection.Query().Where(o => !o.Closed) still travels as a query; (selection, model, db, ctx) => selection.Where(o => !o.Closed) loads the selection in the grid's request - within the same 1000-record limit - and hands the command the ids of the records it kept.
A query cannot travel through a URL or a form, so the grid stores it on the server and hands the command only a key, which the command resolves back into the query. This works the same in both execution modes. Keep in mind:
- The key belongs to the user who selected the rows and expires after 4 hours. An expired or unknown key fails with "The selected data is no longer available. Please refresh the page and try again." - the user has to go back to the grid and select again. The command never silently runs over a different set of records.
- In the command window, a multiselect loads the selection. If the command's page shows the Entity Collection in a multiselect, opening the window loads the selected records, within the same 1000-record limit. Leave the field out of the page when the selection can be large.
- The selection is a query, not a snapshot. It is executed again when the command runs, so records changed in the meantime (e.g. by another user) can move in or out of it if they no longer match the data source, the filters or the Enabled condition.