The Syncfusion Blazor TreeGrid is a feature-rich component used to visualize self-referential hierarchical (tree-like structure) data effectively in a tabular format. Its features include data binding, editing, sorting, filtering, paging, aggregating rows, and exporting to Excel, CSV, and PDF formats.
In this blog, we are going to discuss the improvements made to the Blazor TreeGrid’s performance in WASM (WebAssembly) applications for the 2020 Volume 3 SP1 release, compared to the previous release version (18.3.0.44). The comparison is fully based on the performance best practice guidelines suggested in the Blazor WebAssembly application documentation.
We received various requests from our customers about improving the TreeGrid’s performance in Blazor WebAssembly applications. So, in response, we took immediate action and improved the performance of the following features in Blazor WebAssembly:
Even though we improved the Blazor TreeGrid’s performance at the source level, the following Blazor WebAssembly behaviors needed to be avoided on the application side while using Blazor TreeGrid events to improve performance further:
Each cell in the TreeGrid component and its child component will be checked for re-rendering by the Blazor diffing algorithm. For instance, the EventCallBack method in the application or TreeGrid will check every child component once the event callback is completed.
The newly provided PreventRender method helps you avoid unnecessary re-rendering of the TreeGrid component. This method internally overrides the ShouldRender method of the TreeGrid to prevent rendering.
In the following example:
<button class="btn btn-primary" @>Notes:
When a callback method is assigned to the TreeGrid event, the StateHasChanged method will be called in the parent component of the TreeGrid after the completion of the event. This would thereby initiate re-rendering.
You can prevent this re-rendering of the TreeGrid component by setting the PreventRender property of the corresponding event argument to true.
In the following example:
<SfTreeGrid @ref="treeGrid" DataSource="@TreeData" AllowPaging="true" IdMapping="TaskID" ParentIdMapping="ParentID" TreeColumnIndex="2"> <TreeGridPageSettings PageSize="2"></TreeGridPageSettings> <TreeGridSelectionSettings PersistSelection="true"></TreeGridSelectionSettings> <TreeGridEvents TValue="SelfReferenceData" RowSelected="OnRowSelected"></TreeGridEvents> <TreeGridColumns> <TreeGridColumn Type="ColumnType.CheckBox" Width="50"></TreeGridColumn> <TreeGridColumn Field="TaskID" HeaderText="Task ID" IsPrimaryKey="true" Width="80" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn> <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="240"></TreeGridColumn> <TreeGridColumn Field="Duration" HeaderText="Duration" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn> <TreeGridColumn Field="Progress" HeaderText="Progress" Width="100"></TreeGridColumn> <TreeGridColumn Field="StartDate" HeaderText="StartDate" Width="100"></TreeGridColumn> </TreeGridColumns> </SfTreeGrid> @code{ public List<SelfReferenceData> TreeData { get; set; } SelfReferenceData SelectedTask = new SelfReferenceData { }; private void OnRowSelected(RowSelectEventArgs<SelfReferenceData> args) { args.PreventRender = true; //without this, you may see noticeable delay in selection with 75 rows in tree grid. SelectedTask = args.Data; } protected override void OnInitialized() { TreeData = SelfReferenceData.GetTree(); } public class SelfReferenceData { public static List<SelfReferenceData> tree = new List<SelfReferenceData>(); public int? TaskID { get; set; } public string TaskName { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public String Progress { get; set; } public String Priority { get; set; } public int Duration { get; set; } public int? ParentID { get; set; } public bool? isParent { get; set; } public SelfReferenceData() { } public static List<SelfReferenceData> GetTree() { if (tree.Count == 0) { int root = -1; for (var t = 1; t <= 10; t++) { Random ran = new Random(); string math = (ran.Next() % 3) == 0 ? "High" : (ran.Next() % 2) == 0 ? "Release Breaker" : "Critical"; string progr = (ran.Next() % 3) == 0 ? "Started" : (ran.Next() % 2) == 0 ? "Open" : "In Progress"; root++; int rootItem = tree.Count + root + 1; tree.Add(new SelfReferenceData() { TaskID = rootItem, TaskName = "Parent Task " + rootItem.ToString(), StartDate = new DateTime(1992, 06, 07), EndDate = new DateTime(1994, 08, 25), isParent = true, Progress = progr, Priority = math, Duration = ran.Next(1, 50) }); int parent = tree.Count; for (var c = 0; c <= 2; c++) { root++; string val = ((parent + c + 1) % 3 == 0) ? "Low" : "Critical"; int parn = parent + c + 1; progr = (ran.Next() % 3) == 0 ? "In Progress" : (ran.Next() % 2) == 0 ? "Open" : "Validated"; int iD = tree.Count + root + 1; tree.Add(new SelfReferenceData() { TaskID = iD, TaskName = "Child Task " + iD.ToString(), StartDate = new DateTime(1992, 06, 07), EndDate = new DateTime(1994, 08, 25), isParent = (((parent + c + 1) % 3) == 0), ParentID = rootItem, Progress = progr, Priority = val, Duration = ran.Next(1, 50) }); if ((((parent + c + 1) % 3) == 0)) { int immParent = tree.Count; for (var s = 0; s <= 1; s++) { root++; string Prior = (immParent % 2 == 0) ? "Validated" : "Normal"; tree.Add(new SelfReferenceData() { TaskID = tree.Count + root + 1, TaskName = "Sub Task " + (tree.Count + root + 1).ToString(), StartDate = new DateTime(1992, 06, 07), EndDate = new DateTime(1994, 08, 25), isParent = false, ParentID = iD, Progress = (immParent % 2 == 0) ? "On Progress" : "Closed", Priority = Prior, Duration = ran.Next(1, 50) }); } } } } } return tree; } } }
Notes:
The following metrics were taken after rendering 5,000 records with 100 records per page with pagination.
TreeGrid Action | Improvement from Volume 2 to Volume 3 (Using .NET 5) |
Initial Load | ~+73% |
Filtering | ~+74% |
Clear Filtering | ~+80% |
Sorting | ~+85% |
Paging | ~+75% |
Selection | ~+90% |
Column Chooser | ~+69% |
Column Menu | ~+72% |
Column Resizing | ~+88% |
The Blazor TreeGrid renders each row and cell as an individual component. Loading large numbers of rows and cells in the view will have a performance impact on both memory consumption and CPU processing.
To use a TreeGrid without such performance impacts, you can load a reduced set of rows in the TreeGrid using paging and virtualization features.
Note: Even with the paging or virtualization feature enabled, having hundreds of rows in a single TreeGrid page will lead to performance lag in an application. So, you need to set a reasonable page size in any scenario.
Thanks for reading! In this blog, we talked about the Blazor TreeGrid’s performance improvement in WebAssembly apps in the 2020 Volume 3 SP1 release. This is done by avoiding rendering unnecessary components. Try it out and leave your feedback in the comments section below.
For existing customers, the newest version of Essential Studio® is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out our available features.
You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!