Install
$ agentstack add skill-devexpress-agent-skills-devexpress-blazor-treelist ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
DevExpress Blazor TreeList
DxTreeList is a hierarchical data grid for Blazor. It displays data as a tree with expandable/collapsible rows based on parent-child key relationships. It shares most of DxGrid's feature set — sorting, filtering, CRUD editing, export, selection — and adds tree-specific capabilities such as multi-level expand/collapse, load-on-demand child nodes, and tree filtering modes.
When to Use This Skill
- Display hierarchical data (organizational charts, product categories, file systems, bill of materials)
- Bind flat data with parent-child ID relationships (
KeyFieldName+ParentKeyFieldName) - Sort, filter, or page tree nodes
- Implement CRUD for hierarchical data (create, edit, delete nodes)
- Export tree data to CSV, XLS/XLSX, or PDF
- Load child nodes on demand from a remote API
- Select single or multiple tree nodes with checkboxes
- Reorder tree nodes within the TreeList or move rows between TreeLists and Grids with drag-and-drop
- Change node hierarchy (re-parent nodes) via drag-and-drop
Prerequisites & Installation
NuGet Package
| Package | Purpose | |---|---| | DevExpress.Blazor | TreeList + all standard Blazor UI components |
# Install from NuGet.org:
dotnet add package DevExpress.Blazor
Setup (existing project)
- Register DevExpress resources in
Program.cs:
``csharp builder.Services.AddDevExpressBlazor(); ` > **v26.1 note**: DevExpress.Blazor no longer includes options.BootstrapVersion or DevExpress.Blazor.BootstrapVersion`. Do not generate either API.
- Apply a theme and add client scripts in
App.razorinside ``:
``razor @using DevExpress.Blazor @DxResourceManager.RegisterTheme(Themes.Fluent) @DxResourceManager.RegisterScripts() ``
- Add the namespace to
_Imports.razor:
``razor @using DevExpress.Blazor ``
Before You Start — Ask the Developer
Before generating code, ask:
- Render mode: Are you using
InteractiveServer,InteractiveWebAssembly, orInteractiveAuto? (TreeList requires an interactive render mode for tree expansion, filtering, and editing.) - Data structure: Is your data a flat list with parent ID references, or is it already a nested object graph?
- Key fields: What are the primary key field and the parent key field names? What is the root value (the parent ID of root nodes —
null,0, or something else)? - Features needed: Do you need editing? Export? Selection? Load-on-demand children?
- New or existing project?: Are you adding the TreeList to an existing project or starting fresh?
Component Overview
DxTreeList provides:
- Data Binding (
Data,KeyFieldName,ParentKeyFieldName): Binds flat data with parent-child relationships;RootValuedefines root nodes - Column Types (
DxTreeListDataColumn,DxTreeListCommandColumn,DxTreeListSelectionColumn,DxTreeListBandColumn): Same column model as DxGrid - Tree Navigation (
AllowExpandCollapse,ExpandedRowKeys): Expand/collapse tree levels, expand all, collapse all - Data Shaping (
AllowSort,ShowSearchBox,FilterPanelDisplayMode): Sort, filter row, filter panel, search box - Editing (
EditMode,EditModelSaving,DataItemDeleting): EditRow, EditForm, PopupEditForm, EditCell - Selection (
SelectionMode,SelectedDataItems): Single and multiple node selection - Export (
ExportToCsvAsync,ExportToXlsxAsync,ExportToPdfAsync): CSV, XLS/XLSX, PDF - Load on Demand (
ChildrenLoadedevent): Load child nodes asynchronously when a node is expanded - Summary (
TotalSummary,DxTreeListSummaryItem): Total aggregate summaries — Sum, Min, Max, Avg, Count — displayed in the footer - Focused Row (
FocusedRowEnabled): Highlights a single row on click; useGetFocusedRowIndex(),GetFocusedDataItem(), andSetFocusedRowIndex()to work with the current row - Toolbar (
ToolbarTemplate): Embed a toolbar at the top of the TreeList with custom action buttons and data shaping controls - Drag-and-Drop (
AllowDragRows,AllowedDropTarget,ItemsDropped): Row reordering within the same TreeList, moving rows between TreeLists and Grids, and changing node hierarchy (re-parenting); requiresObservableCollectionfor automatic UI refresh
Core Entry Point (Razor)
@rendermode InteractiveServer
Documentation & Navigation Guide
Getting Started
📄 [references/getting-started.md](references/getting-started.md)
When you need to:
- Set up the TreeList from scratch
- Create your first hierarchical data display
- Understand key field configuration
Data Binding
📄 [references/data-binding.md](references/data-binding.md)
When you need to:
- Bind to flat data with
KeyFieldName/ParentKeyFieldName - Configure
RootValuefor non-null/non-zero root nodes - Load child nodes on demand with the
ChildrenLoadedevent
Editing & Validation
📄 [references/editing-and-validation.md](references/editing-and-validation.md)
When you need to:
- Enable CRUD for tree nodes
- Add / edit / delete nodes with
EditModelSavingandDataItemDeleting - Customize the edit form
- Open the edit form from a toolbar or external button for the current focused or selected row
Data Shaping
📄 [references/data-shaping.md](references/data-shaping.md)
When you need to:
- Sort by columns, add filter row, search box
- Create total or group summaries
- Show the filter panel or customize filter-builder operators for a specific field
Export
📄 [references/export.md](references/export.md)
When you need to:
- Export tree data to CSV, XLSX, or PDF
- Control which rows are exported (expanded, all, selected)
Drag-and-Drop
📄 [references/drag-and-drop.md](references/drag-and-drop.md)
When you need to:
- Reorder rows within the TreeList
- Move rows between TreeLists or Grids
- Change node hierarchy (re-parent nodes) via drag-and-drop
- Handle the
ItemsDroppedevent to update the data source
Examples
💻 [examples/quickstart.razor](examples/quickstart.razor) — Hierarchical CRUD with CustomizeEditModel, search box, summaries, and export 💻 [examples/edit-form-selected-item.razor](examples/edit-form-selected-item.razor) — EditFormTemplate plus an external button that edits the current selected/focused row 💻 [examples/filter-panel-custom-date-operators.razor](examples/filter-panel-custom-date-operators.razor) — FilterPanelDisplayMode with a custom Filter Builder that removes month operators for DueDate 💻 [examples/load-on-demand.razor](examples/load-on-demand.razor) — Async child loading via ChildrenLoaded for large trees
Quick Start Example
@page "/treelist-demo"
@rendermode InteractiveServer
@code {
List Tasks { get; set; }
protected override void OnInitialized() {
Tasks = new List {
new TaskItem { Id = 1, ParentId = 0, Name = "Project Alpha", AssignedTo = "Alice", StartDate = DateTime.Today, DueDate = DateTime.Today.AddMonths(3), Status = "Active" },
new TaskItem { Id = 2, ParentId = 1, Name = "Design Phase", AssignedTo = "Bob", StartDate = DateTime.Today, DueDate = DateTime.Today.AddDays(30), Status = "In Progress" },
new TaskItem { Id = 3, ParentId = 1, Name = "Development Phase", AssignedTo = "Carol", StartDate = DateTime.Today.AddDays(31), DueDate = DateTime.Today.AddDays(90), Status = "Pending" },
new TaskItem { Id = 4, ParentId = 3, Name = "Backend API", AssignedTo = "Dave", StartDate = DateTime.Today.AddDays(31), DueDate = DateTime.Today.AddDays(60), Status = "Pending" },
new TaskItem { Id = 5, ParentId = 3, Name = "Frontend UI", AssignedTo = "Eve", StartDate = DateTime.Today.AddDays(61), DueDate = DateTime.Today.AddDays(90), Status = "Pending" },
};
}
async Task OnEditModelSaving(TreeListEditModelSavingEventArgs e) {
var model = (TaskItem)e.EditModel;
if (e.IsNew) {
model.Id = Tasks.Max(t => t.Id) + 1;
Tasks.Add(model);
} else {
e.CopyChangesToDataItem();
}
}
async Task OnDataItemDeleting(TreeListDataItemDeletingEventArgs e) {
var item = (TaskItem)e.DataItem;
// Remove the item and all its descendants
RemoveWithDescendants(item.Id);
}
void RemoveWithDescendants(int id) {
var children = Tasks.Where(t => t.ParentId == id).Select(t => t.Id).ToList();
foreach (var childId in children)
RemoveWithDescendants(childId);
Tasks.RemoveAll(t => t.Id == id);
}
class TaskItem {
public int Id { get; set; }
public int ParentId { get; set; }
public string Name { get; set; }
public string AssignedTo { get; set; }
public DateTime StartDate { get; set; }
public DateTime DueDate { get; set; }
public string Status { get; set; }
}
}
Key Properties & API Surface
DxTreeList
| Property / Method | Type | Description | |---|---|---| | Data | object | Data source (IEnumerable or IListSource) | | KeyFieldName | string | Unique key field for tree node identification | | ParentKeyFieldName | string | Field containing each node's parent key | | RootValue | object | Parent key value of root nodes (default: null) | | EditMode | TreeListEditMode | EditRow, EditForm, PopupEditForm, EditCell | | SelectionMode | TreeListSelectionMode | Single or Multiple | | SelectedDataItems | IReadOnlyList | Currently selected items (two-way bindable) | | PageSize | int | Rows per page | | ShowSearchBox | bool | Show/hide the search box | | AllowSort | bool | Enable/disable column sorting | | ExportToCsvAsync() | Task | Export to CSV | | ExportToXlsxAsync() | Task | Export to XLS/XLSX | | ExportToPdfAsync() | Task | Export to PDF |
DxTreeListDataColumn
| Property | Type | Description | |---|---|---| | FieldName | string | Data field name (required) | | Caption | string | Column header text | | Width | string | Column width | | DisplayFormat | string | Value format string | | SortOrder | TreeListColumnSortOrder | Ascending or Descending | | SortIndex | int | Multi-column sort position | | AllowSort | bool | Allow user sorting |
Key Differences from DxGrid
| Feature | DxGrid | DxTreeList | |---|---|---| | Data structure | Flat | Hierarchical (parent-child) | | Grouping | GroupIndex on columns | Built-in tree hierarchy | | Group Panel | ShowGroupPanel | Not applicable | | Group Summaries | ` | Not applicable | | Child load on demand | Not available | ChildrenLoaded event | | Filter tree mode | Not applicable | TreeListColumnFilterMode` |
Common Patterns
Pattern 1: Load Child Nodes on Demand
@code {
List RootNodes { get; set; }
protected override async Task OnInitializedAsync() {
RootNodes = await DataService.GetRootNodesAsync();
}
async Task OnChildrenLoaded(TreeListChildrenLoadingEventArgs e) {
var parentId = ((TreeNode)e.DataItem).Id;
var children = await DataService.GetChildrenAsync(parentId);
e.Children = children;
}
}
Pattern 2: Expand/Collapse All Programmatically
// Expand all nodes
TreeList.ExpandAll();
// Collapse all nodes
TreeList.CollapseAll();
// Expand a specific row by its visible index
TreeList.ExpandRow(visibleIndex);
Pattern 3: Export Expanded Rows Only
await TreeList.ExportToXlsxAsync("tree.xlsx", new TreeListXlExportOptions {
RowExpandMode = TreeListExportRowExpandMode.Expanded
});
Troubleshooting
| Symptom | Cause | Fix | |---|---|---| | All rows appear at root level, no hierarchy | ParentKeyFieldName not set or doesn't match data | Verify ParentKeyFieldName matches the parent ID property name exactly | | Root nodes don't appear | RootValue mismatch | If root nodes have ParentId = 0, set RootValue="@((object)0)" — @0 is invalid Razor syntax (RZ1005) | | Tree doesn't expand (clicks ignored) | Static render mode | Add @rendermode InteractiveServer to the page | | Editing creates rows at root level | New row ParentId not initialized | Use CustomizeEditModel to set the ParentId for new child nodes | | Children not shown after data reload | TreeList state not refreshed | Call TreeList.Reload() after updating data | | "Enumeration type XXX not registered for parse operation" | Custom enum used in TreeList filter criteria | Call EnumProcessingHelper.RegisterEnum() in Program.cs before builder.Build() | | "Unhandled exception on the current circuit" with no detail | CircuitOptions.DetailedErrors not set | Add builder.Services.Configure(o => o.DetailedErrors = true); in Program.cs (development only) | | "Component parameter 'ValueChanged' is used two or more times" compile error | @bind-Value and ValueChanged used together | Use @bind-Value="@val" for two-way binding, or Value="@val" ValueChanged="@handler" — never both simultaneously | | dx-blazor.js not found (404) behind a reverse proxy | Reverse proxy strips the app base path | Add app.UsePathBase("/subpath") before app.MapBlazorHub(), or set ` in App.razor | | Static assets return 404 (dx-blazor.css, dx-blazor.js) | UseStaticWebAssets() not called | Add app.UseStaticWebAssets(); in Program.cs before app.UseStaticFiles() | | "Could not find 'X' in 'window.DxBlazor'" JavaScript error | Stale browser-cached JS from an older DevExpress version | Hard-refresh the browser (Ctrl+Shift+R), clear site data, or verify all DevExpress NuGet packages are the same version | | "Cannot pass the parameter 'X' to component 'Y' with rendermode" | Non-serializable parameter passed across a render mode boundary | Move the component to a child .razor file with its own @rendermode` directive; pass only serializable parameters |
Constraints & Rules
- Never invent API: If a property, method, event, or feature is not documented in this skill or its references, do not assume it exists. When asked about an unfamiliar API, first try to verify it using the DevExpress documentation MCP (
devexpress_docs_search) or the localapidoc/folder. Only after checking: if confirmed, use the API; if not found, explicitly state that it does not appear to be part of theDxTreeListAPI. Do not warn that a feature "may have been introduced in a recent version" as a way to justify inventing it. - Programmatic editing uses row indexes: For existing rows, use
StartEditRowAsync(...), not Grid-only APIs such asStartEditDataItemAsync(...). For toolbar or external edit buttons, callStartEditRowAsync(TreeList.GetFocusedRowIndex()). To add a child row from code, useStartEditNewRowAsync(parentVisibleIndex). - Cast edit models explicitly:
EditFormTemplateand event args exposeEditModelasobject. Cast it to your model type before you access properties such asName. - Filter panel API: Use
FilterPanelDisplayMode, notShowFilterPanel. Set it toAlwaysorAutodepending on whether the panel should always be visible. - Filter builder operators: To change date operators such as
IsJanuaryfor a specific field, customizeDxFilterBuilderinsideFilterBuilderTemplate.DxTreeList.CustomizeFilterMenuonly affects the column filter menu andDxTreeListDataColumn.CustomizeFilterMenudoes not exist. - Render mode:
DxTreeListrequires an interactive render mode for
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: DevExpress
- Source: DevExpress/agent-skills
- License: MIT
- Homepage: https://www.devexpress.com
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.