Skip to main content
All docs
V26.1
  • 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.

    Run Demo: Save and Restore the Layout

    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.

    Treelist - Auto Load and Save the Layout

    @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> &#215; 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> &#215; 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");
        }
    }
    

    Run Demo: Save and Restore the Layout

    You can use the following approach to implement different default layouts for mobile and desktop devices:

    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.

    Save and Restore Layout on Demand

    <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> &#215; 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> &#215; 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);
        }
    }
    

    Run Demo: Save and Restore the 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);
    }
    
    Footnotes
    1. Filter criteria can be applied to TreeList data in the following ways:

      Use the GetFilterCriteria() method to obtain all filter criteria, whether applied in code or using the component’s filter UI.