Terminology: 4 deployment stacks (Core includes 3 development modes)
The same Grid is written differently across deployment stacks/modes.Determine the target first, then start; do not mix them.
| Deployment stack | Development mode | Front-end UI syntax | Backend/data model |
|---|---|---|---|
| F.js | — (pure JavaScript) | JS configuration object F.create({...}) |
Pure front-end |
| Pro | WebForms | ASPX server control <f:Grid runat="server"> |
Page_Load/IsPostBack + designer |
| Core | MVC(classic MVC) | Fluent API Html.F().Grid()... |
Controller + ViewBag |
| Core | RazorForms(Core recommended) | TagHelper <f:Grid>(PascalCase) |
Three-piece set + Page_Load/IsPostBack |
| Core | RazorPages | TagHelper <f:Grid>(PascalCase) |
Two-piece set (no designer) + OnGet/OnPost |
| Java | Spring Boot | Thymeleaf dialect <f:grid>(kebab-case) |
Two-piece set (.html + page class .java, no designer) + Page_Load/isPostBack() |
RazorForms and RazorPages share TagHelper tag syntax(
<f:Grid>/<f:RenderField>and other tag names and column attributes are the same), butthey are not exactly the same——the recommended ways to initialize data and attach events differ:
- RazorForms: data is in the backend
Page_LoadinGrid1.DataSource=...; Grid1.DataBind();(<f:Grid>on the tagdo not writeDataSource); buttonOnClick="方法名"。- RazorPages: data is on the taginline
DataSource="@Model.GetXxx()"; buttonOnClick="@Url.Handler(\"方法名\")"。FineUI.Java is the "twin stack" of Core-RazorForms: likewise "tag-based stateful server-side components +
Page_Load/isPostBack()+ control fields +xxx_Click/event handlers", the differenceis only in the backend stack—tags/attributes are all kebab-case(<f:grid>/<f:render-field data-field=…>), the page class uses Java Bean setters/getters (Grid1.setDataSource(...); Grid1.dataBind();), the handlerreturnsvoid(pure JSON incremental postback, no need forUIHelper.Result())。the client-side F.js runtime is exactly the same across all four stacks——F.ui.Grid1.xxx(), render functions,notifySelectedRows('Grid1'), and listener JS remain unchanged. Seefineui-foundation。
When to Use
- Display tabular data, configure columns (text/number/date/formatting/custom rendering)
- Row selection: checkbox multi-select, single select, read selected rows
- Data loading: local inline data / server-side data / server-side paging
- Cell editing, sorting, filtering, grouping, summary rows, toolbar
Before You Start — first determine "which mode"
Determination clues:
.aspx→ Pro(WebForms);Controllers/+Views/*/Index.cshtmland useHtml.F()(Fluent API)→ Core-MVC;Pages/*.cshtmluse<f:Grid>tag → Core-RazorForms(has.designer.cs) or Core-RazorPages(no.designer.cs); pure front-end.html→ F.js;.htmlin<html xmlns:f="http://fineui.com/java">+<f:grid>lowercase tags,pom.xml/mvnw, page class.javawith@FineUIPage(...)+extends FineUIPageBase→ Java(Spring Boot)。
Then confirm:Where does the data come from?(local inline / server-side)Do you need editing? Do you need selection?
Quick overview of each syntax (the same basic table)
// ① F.js
F.create({
type: 'Grid', isFluid: true, id: 'Grid1', renderTo: '#wrap', title: '表格',
idField: 'Id', textField: 'Name',
columns: [
{ columnType: 'rownumberfield' },
{ text: '姓名', field: 'Name' },
{ text: '入学年份', field: 'EntranceYear', fieldType: 'int' },
{ text: '所学专业', field: 'Major', flex: 1, minWidth: 150 }
],
data: [{ Id: 1, Name: '张三', EntranceYear: 2020, Major: '软件工程' }]
});
<%-- ② Pro(WebForms,.aspx)--%>
<f:Grid ID="Grid1" runat="server" IsFluid="true" ShowBorder="true" ShowHeader="true" Title="表格" DataIDField="Id" DataKeyNames="Id">
<Columns>
<f:RowNumberField />
<f:RenderField ColumnID="Name" DataField="Name" HeaderText="姓名" />
<f:RenderField ColumnID="EntranceYear" DataField="EntranceYear" FieldType="Int" HeaderText="入学年份" />
<f:RenderField ColumnID="Major" DataField="Major" ExpandUnusedSpace="true" MinWidth="150px" HeaderText="所学专业" />
</Columns>
</f:Grid>
// ②后台 Grid.aspx.cs
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) { Grid1.DataSource = GetDataTable(); Grid1.DataBind(); }
}
// ③ Core-MVC(Fluent API,Index.cshtml)
@{ var F = Html.F(); }
@(F.Grid().IsFluid(true).Title("表格").ID("Grid1").DataIDField("Id").DataTextField("Name")
.Columns(
F.RowNumberField(),
F.RenderField().HeaderText("姓名").DataField("Name"),
F.RenderField().HeaderText("入学年份").DataField("EntranceYear").FieldType(FieldType.Int),
F.RenderField().HeaderText("所学专业").DataField("Major").ExpandUnusedSpace(true).MinWidth(150)
)
.DataSource(ViewBag.Grid1DataSource) // Controller: ViewBag.Grid1DataSource = GetDataTable();
)
<!-- ④ Core-RazorForms(TagHelper):标签不写 DataSource,数据在后台 Page_Load 绑定 -->
<f:Grid ID="Grid1" IsFluid="true" ShowBorder="true" ShowHeader="true" Title="表格" DataIDField="Id" DataTextField="Name">
<Columns>
<f:RowNumberField />
<f:RenderField HeaderText="姓名" DataField="Name" />
<f:RenderField HeaderText="入学年份" DataField="EntranceYear" FieldType="Int" />
<f:RenderField HeaderText="所学专业" DataField="Major" ExpandUnusedSpace="true" MinWidth="150" />
</Columns>
</f:Grid>
// ④后台 Grid.cshtml.cs(partial,配 designer.cs)
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) { Grid1.DataSource = GetDataTable(); Grid1.DataBind(); }
}
<!-- ⑤ Core-RazorPages(TagHelper):列同④,但数据在标签上内联绑定 -->
<f:Grid ID="Grid1" IsFluid="true" ShowBorder="true" ShowHeader="true" Title="表格"
DataIDField="Id" DataTextField="Name" DataSource="@Model.GetDataTable()">
<Columns>
<%-- 列标签与④完全一致 --%>
</Columns>
</f:Grid>
<!-- ⑥ FineUI.Java(Thymeleaf 方言):标签/属性全 kebab-case;列同④结构,数据在页面类 Page_Load 绑定 -->
<!DOCTYPE html>
<html xmlns:f="http://fineui.com/java" layout:decorate="~{shared/layout}">
<head><title>FineUI.Java · 基础表格</title></head>
<body>
<th:block layout:fragment="body">
<f:grid id="Grid1" is-fluid="true" show-border="true" show-header="true" title="表格" data-id-field="Id" data-text-field="Name">
<f:columns>
<f:row-number-field></f:row-number-field>
<f:render-field header-text="姓名" data-field="Name"></f:render-field>
<f:render-field header-text="入学年份" data-field="EntranceYear" field-type="Int"></f:render-field>
<f:render-field header-text="所学专业" data-field="Major" expand-unused-space="true" min-width="150"></f:render-field>
</f:columns>
</f:grid>
</th:block>
<th:block layout:fragment="script"><script src="/res/js/grid.js"></script></th:block>
</body>
</html>
// ⑥后台 Grid.java(页面类,无 designer;字段名 = 标签 id)
@FineUIPage("grid/grid")
public class Grid extends FineUIPageBase {
com.fineui.java.core.controls.Grid Grid1; // 全限定名避免与本页类名 Grid 冲突;或 import 后写 Grid Grid1;
public void Page_Load(Object sender, EventArgs e) {
if (!isPostBack()) { Grid1.setDataSource(getDataList()); Grid1.dataBind(); }
}
}
Documentation Reference Files
The table is the most complex component, split into 13 reference files by functional category.Read only the relevant articles as needed, no need to read everything.
Basics (data / columns / pagination / selection / editing)
| File | When to read |
|---|---|
| references/columns.md | Column definitions, column types, formatting (date/number), custom rendering, fixed columns |
| references/data-loading.md | In-memory pagination / database pagination, page-change event postback, RecordCount |
| references/editing.md | Cell editing, column editors, reading edited data (API differences across stacks) |
| references/selection.md | Row selection: checkbox multi-select/single-select, default selected, read and set selected rows |
| references/paging-toolbar.md | Pagination toolbar, page size selector, compact pagination for narrow screens, global configuration |
Data processing (sorting / totals / filtering / grouping / tree)
| File | When to read |
|---|---|
| references/sorting.md | Client/server sorting, multi-column sorting, sorting by another field, custom sort function |
| references/summary.md | Total row: client/server, current page/all, floating, multiple rows |
| references/filter.md | Header filtering: text/number/date/dropdown/checkbox, multiple conditions, inline filtering, server-side filtering handling |
| references/row-group.md | Row grouping: group header rendering, expand/collapse, subtotals within a group |
| references/tree-grid.md | Tree grid: parent-child hierarchical rows, checkbox cascade, icons, pagination |
Layout and interaction (headers / row features / advanced)
| File | When to read |
|---|---|
| references/header.md | Header options (hide/menu/tooltip/custom column attributes),multiple headers, dynamically create columns |
| references/row-features.md | Row expand column, modal column, row command buttons, row click/double-click/selection events, row/cell styles, row height and density |
| references/advanced.md | Column locking, column/row drag-and-drop sorting, cell merging, large data grids |
Concepts → property name cross-reference for each syntax (Key Options at a Glance)
Core-RazorForms and Core-RazorPages share the same set of TagHelper properties (the "Core-TagHelper" column in the table below); the differences are in data initialization/events (see Constraints 5, 6 and selection.md).Java columns are listed separately, property names = Core-TagHelper names converted to kebab-case(property "values" such as
Int/Datestill remain PascalCase).
| Concept | F.js | Pro (WebForms) | Core-MVC (Fluent API) | Core-TagHelper | Java (Thymeleaf dialect) |
|---|---|---|---|---|---|
| Component | type: 'Grid' |
<f:Grid runat="server"> |
F.Grid() |
<f:Grid> |
<f:grid> |
| Adaptive width | isFluid: true |
IsFluid="true" |
.IsFluid(true) |
IsFluid="true" |
is-fluid="true" |
| Row ID field | idField |
DataIDField |
.DataIDField() |
DataIDField |
data-id-field |
| Column collection | columns: [ ] |
<Columns> |
.Columns( ) |
<Columns> |
<f:columns> |
| Row number column | columnType:'rownumberfield' |
<f:RowNumberField> |
F.RowNumberField() |
<f:RowNumberField> |
<f:row-number-field> |
| Data field | field |
DataField |
.DataField() |
DataField |
data-field |
| Column title | text |
HeaderText |
.HeaderText() |
HeaderText |
header-text |
| Field type | fieldType |
FieldType |
.FieldType(FieldType.X) |
FieldType |
field-type="Int" |
| Built-in renderer | (fieldType+fieldFormat) | Renderer+RendererArgument |
.Renderer(Renderer.X).RendererArgument() |
Renderer+RendererArgument |
renderer="Date"+renderer-argument |
| Custom JS rendering | renderer: fn |
RendererFunction="fn" |
.RendererFunction("fn") |
RendererFunction="fn" |
renderer-function="fn" |
| Checkbox multi-select | checkboxSelect: true |
EnableCheckBoxSelect="true" |
.EnableCheckBoxSelect(true) |
EnableCheckBoxSelect="true" |
enable-check-box-select="true" |
Related Skills
fineui-foundation:F.create/ PageManager / deployment stack and mode overview / RawHtml security model / naming conventionsfineui-form: form fields used by Grid cell editors and filter fields (TextBox / NumberBox / DropDownList, etc.)fineui-window: Window component used by Grid modal columnsfineui-tree: standalone Tree control (different from the Grid's "tree grid", see tree-grid.md)
Constraints & Rules
- Never make up APIs: for properties you are unsure about, check the official website API (see Official Resources below) or
F/doc/JSDoc, don't guess. Property names differ between modes; in particular, don't use one mode's names in another mode. - Decide on a mode first, don't mix them: A single page uses only one mode's syntax. For how to decide, see "Before you start". F.js uses
text/field, the three C# modes useHeaderText/DataField,Java usesheader-text/data-field(all kebab-case)—don't mix them up; don't mix Fluent API (MVC) with TagHelper (RazorForms/RazorPages). - Text is HTML-encoded by default (RawHtml safety model): Grid cell/column header text is escaped by default. To output trusted HTML:
- F.js: column
rendererthe returned string is inserted as HTML (the render function itself must guarantee it is trusted); for plain text properties useF.rawHtml(...)。 - C#: to assign HTML to control text use
xxx.TextRawHtml = new RawHtml("..."); for messages useShowNotify(new RawHtml("..."))。never hand-write the twoText+TextRawproperties。 - Java: Labels use
xxx-raw-html(e.g.header-text-raw-html/text-raw-html), the server side usesnew RawHtml(...)and the corresponding setter; for message instances usenotify.setMessageRawHtml(new RawHtml(...))then callnotify.show(). Don't useencode-text="false"as a general escape hatch for new code. Render function return values are the same as F.js (client-side insertion).
- F.js: column
- Fixed Pro data binding pattern:
!IsPostBackinsideGrid1.DataSource = table; Grid1.DataBind();. Forgetting!IsPostBackwill rebind on every postback and lose state. - The three Core modes each initialize data differently:
- MVC(Fluent API): Controller sets
ViewBag.Grid1DataSource, in the View.DataSource(ViewBag.Grid1DataSource)。 - RazorForms: backend
Page_Load(!IsPostBack) insideGrid1.DataSource=...; Grid1.DataBind();,<f:Grid>tagdo not writeDataSource。 - RazorPages: inline on the tag
DataSource="@Model.GetXxx()"。 - Java (same paradigm as RazorForms): page class
Page_Load(!isPostBack()) insideGrid1.setDataSource(list); Grid1.dataBind();,<f:grid>tagdo not writedata-source; control fieldsdeclare manually in the class(com.fineui.java.core.controls.Grid Grid1;, field name = tagid); event/command handlersreturnvoid(e.g.public void Grid1_PageIndexChanged(Object sender, GridPageEventArgs e))。
- MVC(Fluent API): Controller sets
- RazorForms vs RazorPages (both are TagHelper, but the backend models differ): RazorForms trio (
.cshtml+.cshtml.cspartial +.designer.cs), the backend inherits the project's existing RazorForms page base class (the official example isBaseModel, which itself can inheritPageModel), usesPage_Load/IsPostBack、OnClick="方法名"; synchronous control events returnvoid, a button click example isprotected void 方法名(object sender, EventArgs e), while paging, sorting, row commands, etc. use their own dedicatedEventArgs,do not writeOnPost, do not returnIActionResult, do not callUIHelper.Result(). RazorPages pair (not partial、none designer)、OnGet/OnPostXxx、OnClick="@Url.Handler(\"方法名\")",OnPostXxxreturnsIActionResultandUIHelper.Result();Java pair (.html+.java, no designer),Page_Load/isPostBack()、on-click="方法名"、@FineUIPage("area/page")define routes. - New code uses only columns common to all three stacks: for plain columns use
RenderField, for boolean display columns useRenderCheckField, plusRowNumberField、GroupFieldandRenderField.Commands. Do not generate server-rendered columns that exist only in Pro based on historical FineUI.Pro examples. - Row selection uniformly uses a stable row ID: initialization, reading, and server-side active selection all first set
DataIDField/data-id-field, then useSelectedRowID/SelectedRowIDArray/getSelectedRowIdArray(). Pro/Core'sSelectedRowIndex/SelectedRowIndexArrayis deprecated and is only used to identify and migrate old code; Java has directly removed the getter/setter and template property of the same name. When reading selected row data, Pro / Core-RazorForms callGrid1.GetSelectedDataKeys(), Java callsGrid1.getSelectedDataKeys(); you must makeDataKeyNames/_DataKeyNames/data-key-namesinclude the row ID field. For database pagination cross-page selection or sensitive business, only take the stable row ID, then query the database. See references/selection.md。 - Don't confuse the three "grouping/hierarchy" concepts:Multi-header(grouping of columns,
GroupField,header.md)≠ row grouping(data rows grouped by field,EnableRowGroup,row-group.md)≠ tree table(row parent-child hierarchy,EnableTree,tree-grid.md). When the user says "grouping", first confirm which one it is. - F.js nested configuration vs .NET flattened properties: several advanced features in F.js put options into one object (
tree:{...}/rowGroup:{...}/rowExpander:{...}/filter:{...}), while Pro/Core flattens them into a bunch of independent properties (EnableTree/TreeColumn/...). Pay attention to this structural difference when transcribing. - Row event EventArgs class names differ by stack: for the same row event, the parameter class names of Pro and RazorForms are different (e.g., row command Pro
GridCommandEventArgs/ RazorFormsGridRowCommandEventArgs)。Java's class names are also not completely consistent with Core: row command usesGridCommandEventArgs(same as Pro), row single-click/double-click usesGridRowEventArgs, row data binding usesGridRowDataBoundEventArgs, pagingGridPageEventArgs, sortingGridSortEventArgs(getter retrieves the value, e.g.,e.getRowIndex()/e.getCommandName()). See row-features.md, don't copy it wrong. - Merge/drag have no server-side properties: cell merging (
mergeCells/mergeColumns), row dragging (moveRowUp, etc.) are all client-side methods; column/row order persistence usesF.customEvent+Page_CustomEvent, with structured parameters passed as JSON objects/arrays. See advanced.md。 - Row commands uniformly use
RenderField.Commands: Pro, Core RazorForms, and Java all useRenderField.Commands;Commandbelongs only toRenderField. Client-side additional logic listens to the Grid'srowcommand, server-side declaresOnRowCommand。
Official Resources
- Online API:
- JS:https://fineui.com/js/api/(`FineUI.Grid` /
FineUI.GridColumn) - Pro:https://fineui.com/pro/api/
- Core:https://fineui.com/core/api/
- JS:https://fineui.com/js/api/(`FineUI.Grid` /
- FineUI.Java: control property semantics are consistent with Core (property names in kebab-case, property values the same as Core), and the client-side F.js API is exactly the same as the JS side; when looking up properties, first check the Core API and then convert to kebab-case according to the naming convention.
- For the official website example library and documentation, see https://www.fineui.com/