Save and Restore Layout in Blazor TreeList
- 7 minutes to read
Users can change the TreeList layout while using your application. They can resize or reorder columns, change the page size, and filter data. You can save these layout settings and restore them later, for example, when a user reopens the page.
Layout Settings
A TreeListPersistentLayout object stores the following TreeList layout settings:
| Saved Information | TreeList Property | TreeListPersistentLayout Property |
|---|---|---|
| Current page index | DxTreeList.PageIndex | Layout.PageIndex |
| Page size | DxTreeList.PageSize | Layout.PageSize |
| Single-page or multi-page data display | DxTreeList.ShowAllRows | Layout.ShowAllRows |
| Search text | DxTreeList.SearchText | Layout.SearchText |
| Filter values | TreeList column filter criteria[1] joined by AND operators |
Layout.FilterCriteria |
| Individual column settings (refer to the table below) | - | Layout.Columns.Item(i) |
Important
DevExpress components can incorrectly serialize custom enumeration values in criteria operators. Refer to the following troubleshooting topic for additional information: The XXX enumeration type is not registered for the parse operation…
The TreeListPersistentLayout.Columns collection stores information about column layout settings. Each collection item (TreeListPersistentLayoutColumn) includes the following data:
| Saved Information | TreeList Column Parameter | TreeListPersistentLayoutColumn Property |
|---|---|---|
| Column type | A column type defined in the markup: data, band, command, or selection. | LayoutColumn.ColumnType |
| Data field name | DxTreeListColumn.FieldName | LayoutColumn.FieldName |
| Sort index | DxTreeListColumn.SortIndex | LayoutColumn.SortIndex |
| Sort direction | DxTreeListColumn.SortOrder | LayoutColumn.SortOrder |
| Position | DxTreeListColumn.VisibleIndex | LayoutColumn.VisibleIndex |
| Visibility | DxTreeListColumn.Visible | LayoutColumn.Visible |
| Width | DxTreeListColumn.Width | LayoutColumn.Width |
Save and Restore Layout Automatically
To save and restore the TreeList layout automatically, handle the following events:
- LayoutAutoSaving
- Fires each time the TreeList layout changes and allows you to save the layout.
- LayoutAutoLoading
- Fires once the TreeList component is initialized and allows you to restore the saved layout.
Note: When <DxTreeList> loads a saved layout, it validates the layout against the current TreeList configuration. If the column collection has changed, the TreeList does not restore column settings. Instead, it loads only TreeList-level settings, such as search text, page size, and the current page. Handle the LayoutAutoLoading event to restore column settings.
The following code snippet implements basic layout persistence. When the component layout changes, the LayoutAutoSaving event handler saves the updated layout to the browser’s local storage. Once the page is reloaded or restored, the LayoutAutoLoading event handler loads the most recently saved layout from the local storage and applies it to the TreeList.

@using System.Text.Json
@inject ISpaceObjectDataProvider SpaceObjectDataProvider
@inject IJSRuntime JSRuntime
@if (PreRendered) {
<DxTreeList @ref="TreeList"
Data="TreeListData"
ChildrenFieldName="Satellites"
ShowAllRows="true"
LayoutAutoLoading="TreeList_LayoutAutoLoading"
LayoutAutoSaving="TreeList_LayoutAutoSaving"
ShowFilterRow="true"
AutoExpandAllNodes="true">
<Columns>
<DxTreeListDataColumn FieldName="Name" />
<DxTreeListDataColumn FieldName="TypeOfObject" Caption="Type" FilterRowOperatorType="TreeListFilterRowOperatorType.Equal">
<EditSettings>
<DxComboBoxSettings Data="TreeListRenderHelper.SpaceObjectTypes" SearchMode="@ListSearchMode.AutoSearch"
SearchFilterCondition="@ListSearchFilterCondition.Contains" />
</EditSettings>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="Mass10pow21kg" Caption="Mass, kg" DisplayFormat="N2">
<HeaderCaptionTemplate>Mass, 10<sup>21</sup> × kg</HeaderCaptionTemplate>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="MeanRadiusInKM" Caption="Radius, km" DisplayFormat="N2">
<HeaderCaptionTemplate>Radius, km</HeaderCaptionTemplate>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="Volume10pow9KM3" DisplayFormat="N2" Caption="Volume">
<HeaderCaptionTemplate>Volume, 10<sup>9</sup> × km<sup>3</sup></HeaderCaptionTemplate>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="SurfaceGravity" Caption="Gravity" DisplayFormat="N2">
<HeaderCaptionTemplate>Gravity, m/s<sup>2</sup></HeaderCaptionTemplate>
</DxTreeListDataColumn>
</Columns>
<ToolbarTemplate>
<DxToolbar ItemRenderStyleMode="ToolbarRenderStyleMode.Contained">
<Items>
<DxToolbarItem Text="Reload Page" Click="ReloadPageButton_ClickAsync" BeginGroup="true" />
</Items>
</DxToolbar>
</ToolbarTemplate>
</DxTreeList>
} else {
<em>Loading...</em>
}
@code {
const string LocalStorageKey = "TreeList-LayoutPersistence-Data";
bool PreRendered { get; set; }
ITreeList TreeList { get; set; }
object TreeListData { get; set; }
protected override void OnInitialized() {
TreeListData = SpaceObjectDataProvider.GenerateData();
}
protected override void OnAfterRender(bool firstRender) {
if (firstRender) {
PreRendered = true;
StateHasChanged();
}
}
async Task TreeList_LayoutAutoLoading(TreeListPersistentLayoutEventArgs e) {
e.Layout = await LoadLayoutFromLocalStorageAsync();
}
async Task TreeList_LayoutAutoSaving(TreeListPersistentLayoutEventArgs e) {
await SaveLayoutToLocalStorageAsync(e.Layout);
}
// Refer to https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management/
// to learn more about Blazor state management
// In Blazor Server apps, prefer ASP.NET Core Protected Browser Storage
async Task<TreeListPersistentLayout> LoadLayoutFromLocalStorageAsync() {
try {
var json = await JSRuntime.InvokeAsync<string>("localStorage.getItem", LocalStorageKey);
return JsonSerializer.Deserialize<TreeListPersistentLayout>(json);
} catch {
// Mute exceptions for the server prerender stage
return null;
}
}
async Task SaveLayoutToLocalStorageAsync(TreeListPersistentLayout layout) {
try {
var json = JsonSerializer.Serialize(layout);
await JSRuntime.InvokeVoidAsync("localStorage.setItem", LocalStorageKey, json);
} catch {
// Mute exceptions for the server prerender stage
}
}
async Task RemoveLayoutFromLocalStorageAsync() {
try {
await JSRuntime.InvokeVoidAsync("localStorage.removeItem", LocalStorageKey);
} catch {
// Mute exceptions for the server prerender stage
}
}
async Task ReloadPageButton_ClickAsync() {
await JSRuntime.InvokeVoidAsync("location.reload");
}
}
You can use the following approach to implement different default layouts for mobile and desktop devices:
- Handle the LayoutAutoSaving event. Save layouts to a database instead of browser storage.
- Handle the LayoutAutoLoading event. Use the DxLayoutBreakpoint component to determine the screen size and load the corresponding layout.
Save and Restore Layout on Demand
To save and restore the TreeList layout on demand, for example, in response to a button click, call the following methods:
- SaveLayout()
- Saves information about a TreeList layout.
- LoadLayout(TreeListPersistentLayout)
- Loads a layout and applies it to the TreeList.
The following code snippet displays two buttons: Save Layout and Load Layout. When a user clicks Save Layout, the component saves the current TreeList layout to the Layout parameter. When the user clicks Load Layout, the component loads the most recently saved layout from the Layout parameter and applies it to the TreeList.

<DxTreeList @ref="TreeList"
Data="TreeListData"
ChildrenFieldName="Satellites"
ShowAllRows="true"
ShowFilterRow="true"
ColumnResizeMode="TreeListColumnResizeMode.NextColumn"
TextWrapEnabled="false"
AutoExpandAllNodes="true">
<Columns>
<DxTreeListDataColumn FieldName="Name" />
<DxTreeListDataColumn FieldName="TypeOfObject" Caption="Type" FilterRowOperatorType="TreeListFilterRowOperatorType.Equal">
<EditSettings>
<DxComboBoxSettings Data="TreeListRenderHelper.SpaceObjectTypes" SearchMode="@ListSearchMode.AutoSearch"
SearchFilterCondition="@ListSearchFilterCondition.Contains" />
</EditSettings>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="Mass10pow21kg" Caption="Mass, kg" DisplayFormat="N2">
<HeaderCaptionTemplate>Mass, 10<sup>21</sup> × kg</HeaderCaptionTemplate>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="MeanRadiusInKM" Caption="Radius, km" DisplayFormat="N2">
<HeaderCaptionTemplate>Radius, km</HeaderCaptionTemplate>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="Volume10pow9KM3" DisplayFormat="N2" Caption="Volume">
<HeaderCaptionTemplate>Volume, 10<sup>9</sup> × km<sup>3</sup></HeaderCaptionTemplate>
</DxTreeListDataColumn>
<DxTreeListDataColumn FieldName="SurfaceGravity" Caption="Gravity" DisplayFormat="N2">
<HeaderCaptionTemplate>Gravity, m/s<sup>2</sup></HeaderCaptionTemplate>
</DxTreeListDataColumn>
</Columns>
<ToolbarTemplate>
<DxToolbar ItemRenderStyleMode="ToolbarRenderStyleMode.Contained">
<Items>
<DxToolbarItem Text="Save Layout" Click="OnSaveClick" />
<DxToolbarItem Text="Load Layout" Click="OnLoadClick" />
</Items>
</DxToolbar>
</ToolbarTemplate>
</DxTreeList>
@code {
ITreeList TreeList { get; set; }
object TreeListData { get; set; }
TreeListPersistentLayout Layout { get; set; }
void OnSaveClick() {
Layout = TreeList.SaveLayout();
}
void OnLoadClick() {
TreeList.LoadLayout(Layout);
}
}
Task-Based Examples
Add Custom Settings to a Layout Object
You can save and restore properties that the TreeListPersistentLayout class does not include. Create a structure that stores a TreeListPersistentLayout instance and additional property values, and use TreeList APIs to retrieve and save those values:
namespace ExtendedTreeListLayout.Data {
public class TreeListExtendedLayout {
public TreeListPersistentLayout Layout { get; }
public bool FilterRowVisible { get; }
public bool GroupPanelVisible { get; }
public bool SearchBoxVisible { get; }
public TreeListExtendedLayout(TreeListPersistentLayout layout, bool filterRowVisible, bool groupPanelVisible, bool searchBoxVisible) {
Layout = layout;
FilterRowVisible = filterRowVisible;
SearchBoxVisible = searchBoxVisible;
}
}
}
Exclude a Setting from Saved Layout
You can exclude specific TreeList settings from the saved layout. Clear the corresponding option in the TreeListPersistentLayout object. The following code snippet removes information about applied filters from the layout settings:
async Task TreeList_LayoutAutoSaving(TreeListPersistentLayoutEventArgs e) {
var layout = e.Layout with {
FilterCriteria = null
};
await SaveLayoutToLocalStorageAsync(layout);
}
-
Filter criteria can be applied to TreeList data in the following ways:
- Filter row and filter menu UI elements.
- SetFilterCriteria and SetFieldFilterCriteria methods.
Use the GetFilterCriteria() method to obtain all filter criteria, whether applied in code or using the component’s filter UI.