Column & field expressions
Genie ships an eval-free expression engine (Genie SQL-flavoured) that powers three things: grid column display/styling, editor field rules (required / disabled / hidden / security), and computed values. The same grammar runs on the UI (live, as values change) and on the server (the engine ships a C# port of the interpreter, so field-level security and required-ness are enforced, not just hinted).
The expression grammar
Section titled “The expression grammar”Expressions are SQL-flavoured predicates evaluated against the other field values (or, for grid
columns, the row’s cell values). Reference a field/column by bare name or @Name;
AND/OR/NOT, LIKE, IN, arithmetic, and If(cond, a, b) are supported. Row-action visibility
expressions reference the row as row.Column (see Actions & row actions).
Smart field attributes — Required / Disabled / Hidden
Section titled “Smart field attributes — Required / Disabled / Hidden”Required / Disabled / Hidden on any editor field are “smart” attributes — each holds
either a literal ("true"/"false") or a row-context expression (the merged successors of the
old RequiredExpression/DisabledExpression/HiddenExpression, which no longer exist):
<Text Name="Reason" Required="@Status == 'Reject'" /> <!-- required only when rejecting --><Number Name="Price" Disabled="@Type == 'B'" /> <!-- read-only when Type is B -->Required is re-validated server-side on submit — not just enforced in the UI.
Field-level security — Allow / Deny
Section titled “Field-level security — Allow / Deny”Allow / Deny whitelist / blacklist who may edit a field. Each holds either a comma-separated
role list or a row-context expression; default is editable by all. A field is editable iff
(Allow empty OR allowMatches) AND NOT (Deny matches). A locked field renders read-only in the UI
and — crucially — is enforced server-side on submit: a denied field’s caller-supplied value is
discarded (create → DefaultValue/null, edit → the previous stored value is kept), so tampering with
the raw API cannot change it.
<Number Name="CreditLimit" Allow="Admin,Manager" /> <!-- only these roles may edit --><Text Name="Notes" Deny="@Status == 'Closed'" /> <!-- locked once the row is closed -->Computed values — ValueExpression
Section titled “Computed values — ValueExpression”ValueExpression computes the field’s value and re-runs whenever its inputs change (make the
field Disabled="true" for a read-only computed display). Beyond field references + arithmetic, the
helper sumLines(cart, 'QtyColumn', 'PriceColumn') totals a <CartTable>’s
line items:
<Number Name="TotalAmount" Label="Total" Disabled="true" ValueExpression="sumLines(LineCart, 'Quantity', 'UnitPrice')" />Grid columns — <Columns>
Section titled “Grid columns — <Columns>”<Columns> <Column Name="Id" Hide="true" /> <Column Name="Name" Search="true" /> <Column Name="CreditLimit" Label="Credit" StyleClasses="text-end" Export="false" /> <Column Name="RegisteredOn" Label="Registered" RelativeTime="true" /></Columns>Per result column: Label, Expression (or element body), Style, StyleClasses,
Hide, Export, RolesAllowed (CSV), RelativeTime, Search, IsAttachment,
StyleClassesExpression, Lookup, LookupKey, LookupParam.
Hide— whentrue, the column is hidden by default in the grid, but it still ships to the client (its cell values remain available for row identity, actions, andLookuplinks) and it is listed in the column manager (“Columns” toolbar button) unchecked, so a user can re-enable it. This replaces the legacyStyle="display:none"hack. Use it for key/id columns backing aLookupor for secondary columns most users don’t need. Defaults tofalse.Expression— an optional client-side display expression (Genie SQL-flavored, the same engine asStyleClassesExpressionand field rules) evaluated per row by the UI against the row’s cell values; its result becomes the cell’s displayed text. It is never evaluated server-side — any computation that needs SQL (joins, aggregates, CASE/IIF, badge markup) belongs in the DataSet query instead, and styling/badges are applied client-side viaStyleClasses/StyleClassesExpression.IsAttachment— whentrue, the column’s value is treated as a set of attachment file paths (pipe/comma-separated) and the UI renders the cell as attachment tags (image thumbnails + file pills) instead of plain text. Defaults tofalse.StyleClassesExpression— an optional client-side expression (Genie SQL-flavored, same engine as field rules) evaluated per row against the row’s cell values; its string result is appended to the cell’s CSS classes afterStyleClasses— e.g.If(Status = 'Overdue', 'gx-danger', 'gx-success').Search— marks the column for the toolbar quick-search box (see Actions & row actions).Lookup/LookupKey/LookupParam— turn the column value into a lookup link. When bothLookup(a target view name) andLookupKey(a sibling column supplying the primary key) are set and the row’s key value is non-empty, the cell renders as a clickable link that opens the linked record read-only in a dialog (the target view’s full layout). The key column is typicallyHide-d — its value still ships to the client for the link.LookupParamnames the parameter the key is passed under (defaults toId). The dialog has a View button that navigates to the full/view/{Lookup}?{LookupParam}={key}page. Loading the linked record is gated by the View permission on the target view; if the user lacks it the dialog opens and shows the server error. KeepLookupParamasIdfor the View button to round-trip (the/viewpage readsId).
<Columns> <Column Name="CustomerId" Hide="true" /> <Column Name="CustomerName" Label="Customer" Lookup="Customers" LookupKey="CustomerId" /></Columns>Row-action visibility — DisplayExpression
Section titled “Row-action visibility — DisplayExpression”A row <Action> uses DisplayExpression (or DisplayColumn) for conditional visibility — the same
expression engine, evaluated per row against row.Column. See
Actions & row actions.
Worked example: sample/Inventory/models/views/Products.view.xml — StyleClassesExpression badges,
Lookup links, RelativeTime, IsAttachment, RolesAllowed, plus smart Required/Hidden
expressions, Allow/Deny field security, and a ValueExpression margin.