Search results

Data Binding in Blazor Tree Grid component

08 Apr 2021 / 14 minutes to read

The Tree Grid uses SfDataManager, which supports both RESTful Web Services binding and List binding. The DataSource property can be assigned either using the SfDataManager as child component of the Tree Grid Blazor component or list of business objects. It supports two kinds of data binding method:

  • List binding
  • Remote service binding

List binding

In List binding, data source for rendering the Tree Grid component is retrieved from the same application locally.

Two types of Data binding are possible with the Tree Grid component.

  • Self-Referential Data binding (Flat Data)
  • Hierarchical Data binding

For Self-Referential data binding, you can assign list of business objects to the DataSource property.

For Hierarchy Data binding, the data-source should be assigned as a object array to the Json property of the SfDataManager and the Adaptor property of the SfDataManager should be either RemoteSaveAdaptor or JsonAdaptor.

Self-Referential data binding/Flat Data

Tree Grid is rendered from Self-Referential data structures by providing two fields, IdMapping field and ParentIdMapping field.

  • IdMapping: This field contains unique values used to identify nodes.
  • ParentIdMapping: This field contains values that indicate parent nodes.
Copied to clipboard
@using Syncfusion.Blazor.TreeGrid;

<SfTreeGrid DataSource="@TreeData" IdMapping="TaskId" ParentIdMapping="ParentId" TreeColumnIndex="1">
<TreeGridColumns>
    <TreeGridColumn Field="TaskId" HeaderText="Task ID" Width="80" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="160"></TreeGridColumn>
    <TreeGridColumn Field="Duration" HeaderText="Duration" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Progress" HeaderText="Progress" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
</TreeGridColumns>
</SfTreeGrid>

@code{
   public class BusinessObject
{
    public int TaskId { get; set; }
    public string TaskName { get; set; }
    public int Duration { get; set; }
    public int Progress { get; set; }
    public string Priority { get; set; }
    public int? ParentId { get; set; }
}

public List<BusinessObject> TreeData = new List<BusinessObject>();

protected override void OnInitialized()
{
    TreeData.Add(new BusinessObject() { TaskId = 1, TaskName = "Parent Task 1", Duration = 10, Progress = 70, ParentId = null, Priority = "High" });
    TreeData.Add(new BusinessObject() { TaskId = 2, TaskName = "Child task 1", Duration = 4, Progress = 80, ParentId = 1, Priority = "Normal" });
    TreeData.Add(new BusinessObject() { TaskId = 3, TaskName = "Child Task 2", Duration = 5, Progress = 65, ParentId = 1, Priority = "Critical" });
    TreeData.Add(new BusinessObject() { TaskId = 4, TaskName = "Parent Task 2", Duration = 6, Progress = 77, ParentId = null, Priority = "Low" });
    TreeData.Add(new BusinessObject() { TaskId = 5, TaskName = "Child Task 5", Duration = 9, Progress = 25, ParentId = 4, Priority = "Normal" });
    TreeData.Add(new BusinessObject() { TaskId = 6, TaskName = "Child Task 6", Duration = 9, Progress = 7, ParentId = 5, Priority = "Normal" });
    TreeData.Add(new BusinessObject() { TaskId = 7, TaskName = "Parent Task 3", Duration = 4, Progress = 45, ParentId = null, Priority = "High" });
    TreeData.Add(new BusinessObject() { TaskId = 8, TaskName = "Child Task 7", Duration = 3, Progress = 38, ParentId = 7, Priority = "Critical" });
    TreeData.Add(new BusinessObject() { TaskId = 9, TaskName = "Child Task 8", Duration = 7, Progress = 70, ParentId = 7, Priority = "Low" });
}
}

Hierarchy data binding

The ChildMapping property is used to map the child records in hierarchy data source.

The following code example shows you how to bind the hierarchical list data into the Tree Grid component.

Copied to clipboard
@using Syncfusion.Blazor.TreeGrid;
@using Syncfusion.Blazor.Data;

<SfTreeGrid ChildMapping="Children" TreeColumnIndex="1" DataSource="@TreeData" TValue="BusinessObject" >
<TreeGridColumns>
    <TreeGridColumn Field="TaskId" HeaderText="Task ID" Width="80" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="160"></TreeGridColumn>
    <TreeGridColumn Field="Duration" HeaderText="Duration" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Progress" HeaderText="Progress" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Priority" HeaderText="Priority" Width="80"></TreeGridColumn>
</TreeGridColumns>
</SfTreeGrid>

@code{
public class BusinessObject
{
    public int TaskId { get; set; }
    public string TaskName { get; set; }
    public int Duration { get; set; }
    public int Progress { get; set; }
    public string Priority { get; set; }
    public List<BusinessObject> Children { get; set; }
}
public List<BusinessObject> TreeData = new List<BusinessObject>();
protected override void OnInitialized()
{
    List<BusinessObject> Record1 = new List<BusinessObject>();
    BusinessObject Child1 = new BusinessObject() { TaskId = 2, TaskName = "Plan timeline", Progress = 100, Duration = 5, Priority = "Normal" };
    BusinessObject Child2 = new BusinessObject() { TaskId = 3, TaskName = "Plan budget", Duration = 5, Progress = 100, Priority = "Low" };
    BusinessObject Child3 = new BusinessObject() { TaskId = 4, TaskName = "Allocate resources", Duration = 5, Progress = 100, Priority = "Critical" };
    Record1.Add(Child1);
    Record1.Add(Child2);
    Record1.Add(Child3);
    TreeData.Add(new BusinessObject() { TaskId = 1, TaskName = "Planning", Duration = 10, Progress = 70, Children = Record1, Priority = "High" });


    List<BusinessObject> Record2 = new List<BusinessObject>();
    BusinessObject Child4 = new BusinessObject() { TaskId = 6, TaskName = "Software Specification", Progress = 60, Duration = 3, Priority = "Normal" };
    BusinessObject Child5 = new BusinessObject() { TaskId = 7, TaskName = "Develop Prototype", Duration = 3, Progress = 100, Priority = "Critical" };


    Record2.Add(Child4);
    Record2.Add(Child5);
    TreeData.Add(new BusinessObject() { TaskId = 5, TaskName = "Design", Duration = 3, Progress = 86, Children = Record2, Priority = "High" });
}
}
  • ExpandCollapse State maintenance is not supported for Hierarchy Data.
  • Batch Editing is not supported for Hierarchy Data.
  • PageSizeMode —> All is not supported for Hierarchy Data.
  • Row Drag and Drop feature is not supported for Hierarchy Data.

ExpandoObject binding

Tree Grid is a generic component which is strongly bound to a model type. There are cases when the model type is unknown during compile type. In such cases you can bound data to the tree grid as list of ExpandoObject.

ExpandoObject can be bound to Tree grid by assigning to the DataSource property. Tree Grid can also perform all kind of supported data operations and editing in ExpandoObject.

Copied to clipboard
@using Syncfusion.Blazor.TreeGrid;

<SfTreeGrid DataSource="@TreeData" @ref="TreeGrid" AllowPaging="true" IdMapping="TaskID" ParentIdMapping="ParentID" TreeColumnIndex="1"  Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" })">
<TreeGridPageSettings PageSize="2"></TreeGridPageSettings>
<TreeGridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" Mode="Syncfusion.Blazor.TreeGrid.EditMode.Cell"></TreeGridEditSettings>
<TreeGridColumns>
    <TreeGridColumn Field="TaskID" HeaderText="Task ID" Width="80" IsPrimaryKey="true"></TreeGridColumn>
    <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="100"></TreeGridColumn>
    <TreeGridColumn Field="StartDate" HeaderText="StartDate" Format="d" Width="100"></TreeGridColumn>
    <TreeGridColumn Field="Duration" HeaderText="Duration" Width="80"></TreeGridColumn>
    <TreeGridColumn Field="Progress" HeaderText="Progress" Width="80"></TreeGridColumn>
    <TreeGridColumn Field="Priority" HeaderText="Priority" Width="80"></TreeGridColumn>
</TreeGridColumns>
</SfTreeGrid>
@code {
SfTreeGrid<ExpandoObject> TreeGrid;
public List<ExpandoObject> TreeData { get; set; }
protected override void OnInitialized()
{
    this.TreeData = GetData().ToList();
}
public static List<ExpandoObject> Data = new List<ExpandoObject>();
public static int ParentRecordID { get; set; }
public static int ChildRecordID { get; set; }
public static List<ExpandoObject> GetData()
{
    Data.Clear();
    ParentRecordID = 0;
    ChildRecordID = 0;
    for (var i = 1; i <= 60; i++)
    {
        Random ran = new Random();
        DateTime start = new DateTime(1992, 06, 07);
        int range = (DateTime.Today - start).Days;
        DateTime startingDate = start.AddDays(ran.Next(range));
        dynamic ParentRecord = new ExpandoObject();
        ParentRecord.TaskID = ++ParentRecordID;
        ParentRecord.TaskName = "Parent Task " + i;
        ParentRecord.StartDate = startingDate;
        ParentRecord.Progress = ParentRecordID % 2 == 0 ? "In Progress" : "Open";
        ParentRecord.Priority = ParentRecordID % 2 == 0 ? "High" : "Low";
        ParentRecord.Duration = ParentRecordID % 2 == 0 ? 32 : 76;
        ParentRecord.ParentID = null;
        Data.Add(ParentRecord);
        AddChildRecords(ParentRecordID);
    }
    return Data;
}
public static void AddChildRecords(int ParentId)
{
    for (var i = 1; i < 4; i++)
    {
        Random ran = new Random();
        DateTime start = new DateTime(1992, 06, 07);
        int range = (DateTime.Today - start).Days;
        DateTime startingDate = start.AddDays(ran.Next(range));
        dynamic ChildRecord = new ExpandoObject();
        ChildRecord.TaskID = ++ParentRecordID;
        ChildRecord.TaskName = "Child Task " + ++ChildRecordID;
        ChildRecord.StartDate = startingDate;
        ChildRecord.Progress = ParentRecordID % 3 == 0 ? "Validated" : "Closed";
        ChildRecord.Priority = ParentRecordID % 3 == 0 ? "Low" : "Critical";
        ChildRecord.Duration = ParentRecordID % 3 == 0 ? 64 : 98;
        ChildRecord.ParentID = ParentId;
        Data.Add(ChildRecord);
    }
}
}

Herewith we have provided list of reserved properties and the purpose used in TreeGrid. We recommend to avoid these reserved properties for Internal purpose(To get rid of conflicts).

Reserved keywords Purpose
childRecords Specifies the childRecords of a parentData
hasChildRecords Specifies whether the record contains child records
hasFilteredChildRecords Specifies whether the record contains filtered child records
expanded Specifies whether the child records are expanded
parentRecord Specifies the parentItem of childRecords
index Specifies the index of current record
level Specifies the hierarchy level of record
filterLevel Specifies the hierarchy level of filtered record
parentIdMapping Specifies the parentID
uniqueID Specifies the unique ID of a record
parentUniqueID Specifies the parent Unique ID of a record
checkboxState Specifies the checkbox state of a record

Remote Service binding

To bind remote data to Tree Grid component, assign service data as an instance of SfDataManager to the DataSource property. To interact with remote data source, provide the endpoint url and define the HasChildMapping property of tree grid.

The HasChildMapping property maps the field name in data source, that denotes whether current record holds any child records. This is useful internally to show expand icon while binding child data on demand.

The Tree Grid provides Load on Demand support for rendering remote data. The Load on demand is considered in Tree Grid for the following actions.

  • Expanding root nodes.
  • Navigating pages, with paging enabled in Tree Grid.

When load on demand is enabled, all the root nodes are rendered in collapsed state at initial load.

When load on demand support is enabled in Tree Grid with paging, the current or active page’s root node alone will be rendered in collapsed state. On expanding the root node, the child nodes will be loaded from the remote server.

When a root node is expanded, its child nodes are rendered and are cached locally, such that on consecutive expand/collapse actions on root node, the child nodes are loaded from the cache instead from the remote server.

Similarly, if the user navigates to a new page, the root nodes of that specific page, will be rendered with request to the remote server.

Copied to clipboard
@using Syncfusion.Blazor.TreeGrid;
@using Syncfusion.Blazor.Data;

<SfTreeGrid IdMapping="TaskID" TValue="BusinessObject" ParentIdMapping="ParentItem" HasChildMapping="isParent" AllowPaging="true" TreeColumnIndex="1">
<SfDataManager Url="https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData" CrossDomain="true" Adaptor="Syncfusion.Blazor.Adaptors.WebApiAdaptor"></SfDataManager>
<TreeGridColumns>
    <TreeGridColumn Field="TaskID" HeaderText="Task ID" Width="80" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="160"></TreeGridColumn>
    <TreeGridColumn Field="Duration" HeaderText="Duration" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Progress" HeaderText="Progress" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Priority" HeaderText="Priority" Width="80"></TreeGridColumn>
</TreeGridColumns>
</SfTreeGrid>

@code{
public class BusinessObject
{
    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 double? Duration { get; set; }
    public int? ParentID { get; set; }
    public bool? isParent { get; set; }
    public bool? Approved { get; set; }
    public int? ParentItem { get; set; }
}
}
  • By default, SfDataManager uses ODataAdaptor for remote data-binding.
  • Based on the RESTful web services, set the corresponding adaptor to SfDataManager. Refer here for more details.
  • Filtering and searching server-side data operations are not supported in load on demand

Offline mode

On remote data binding, all tree grid actions such as paging, loading child on-demand, will be processed on server-side. To avoid postback, set the tree grid to load all data on initialization and make the actions process in client-side. To enable this behavior, use the offline property of SfDataManager.

Copied to clipboard
@using Syncfusion.Blazor.TreeGrid;
@using Syncfusion.Blazor.Data;

<SfTreeGrid IdMapping="TaskID" TValue="BusinessObject" ParentIdMapping="ParentItem" HasChildMapping="isParent" AllowPaging="true" TreeColumnIndex="1">
<SfDataManager Url="https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData" Offline="true" CrossDomain="true" Adaptor="Syncfusion.Blazor.Adaptors.WebApiAdaptor"></SfDataManager>
<TreeGridColumns>
    <TreeGridColumn Field="TaskID" HeaderText="Task ID" Width="80" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="160"></TreeGridColumn>
    <TreeGridColumn Field="Duration" HeaderText="Duration" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Progress" HeaderText="Progress" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Priority" HeaderText="Priority" Width="80"></TreeGridColumn>
</TreeGridColumns>
</SfTreeGrid>

LoadChildOnDemand

Tree Grid provides option to load the child records also during the initial rendering itself for remote data binding by setting LoadChildOnDemand as true.

When LoadChildOnDemand is enabled parent records are rendered in expanded state.

The following code example describes the behavior of the LoadChildOnDemand feature of Tree Grid.

index.razor
treegriddata.cs
DefaultController.cs
Copied to clipboard
@using TreeGridComponent.Data;
@using Syncfusion.Blazor.TreeGrid;

<SfTreeGrid @ref="grid" TValue="SelfReferenceData" LoadChildOnDemand="true" HasChildMapping="isParent" Height="315" IdMapping="TaskID" ParentIdMapping="ParentID" TreeColumnIndex="1" AllowPaging="true">
    <SfDataManager Url="api/Default" Adaptor="Adaptors.WebApiAdaptor" CrossDomain="true"></SfDataManager>
    <TreeGridPageSettings PageSize="2"></TreeGridPageSettings>
    <TreeGridColumns>
        <TreeGridColumn Field="TaskID" HeaderText="Task ID" IsPrimaryKey="true" Width="80" TextAlign="TextAlign.Right"></TreeGridColumn>
        <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="145"></TreeGridColumn>
        <TreeGridColumn Field="Duration" HeaderText="Duration" Width="100" TextAlign="TextAlign.Right"></TreeGridColumn>
        <TreeGridColumn Field="Progress" HeaderText="Progress" Width="100"></TreeGridColumn>
        <TreeGridColumn Field="Priority" HeaderText="Priority" Width="100"></TreeGridColumn>
    </TreeGridColumns>
</SfTreeGrid>
Copied to clipboard
namespace TreeGridComponent.Data {

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()
        {
            tree.Clear();
            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 < 3; 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;
        }
}
Copied to clipboard
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Syncfusion.Blazor;
using Syncfusion.Blazor.Data;
using WebAPI.Data;

namespace WebAPI.Controller
{
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        public static List<SelfReferenceData> FlatData = new List<SelfReferenceData>();
        // GET: api/Default
        [HttpGet]
        public async Task<object> Get(int? code)
        {
            var queryString = Request.Query;
            FlatData.Clear();
            if (SelfReferenceData.tree.Count == 0)
                SelfReferenceData.GetTree();
            List<SelfReferenceData> data = SelfReferenceData.tree.ToList();
            bool isFiltered = false;
            if (queryString.Keys.Contains("$filter"))
            {
                StringValues filter;
                isFiltered = true;
                queryString.TryGetValue("$filter", out filter);
                string[] filterQuery = null;
                if (filter[0].IndexOf('(') != -1 && filter[0].IndexOf(')') != -1)
                {
                    filterQuery = filter[0].Split('(', ')')[1].Split(" eq ");
                }
                else
                {
                    filterQuery = filter[0].Split(" eq ");
                }
                var field = filterQuery[0];
                var value = filterQuery[1];
                if (field == "ParentID" && value == "null")
                {
                    data = data.Where(p => p.ParentID == null).ToList();
                }
            }
            if (queryString.Keys.Contains("$orderby"))
            {
                StringValues srt;
                queryString.TryGetValue("$orderby", out srt);
                srt = srt.ToString().Replace("desc", "descending");
                IQueryable<SelfReferenceData> data1 = SortingExtend.Sort(data.AsQueryable(), srt);
                data = data1.ToList();
            }
            int count = data.Count;
            if (queryString.Keys.Contains("$inlinecount"))
            {
                StringValues Skip;
                StringValues Take;
                int skip = (queryString.TryGetValue("$skip", out Skip)) ? Convert.ToInt32(Skip[0]) : 0;
                int top = (queryString.TryGetValue("$top", out Take)) ? Convert.ToInt32(Take[0]) : data.Count();
                FlatData = data.Skip(skip).Take(top).ToList();
                var GroupData = SelfReferenceData.tree.ToList().GroupBy(rec => rec.ParentID)
                                .Where(g => g.Key != null).ToDictionary(g => g.Key?.ToString(), g => g.ToList());
                foreach (var Record in FlatData.ToList())
                {
                    if (GroupData.ContainsKey(Record.TaskID.ToString()))
                    {
                        var ChildGroup = GroupData[Record.TaskID.ToString()];
                        if (ChildGroup?.Count > 0)
                            AppendChildren(ChildGroup, Record, GroupData);   /////   appending the child records for the respective parent records
                    }
                }
                return new { Items = FlatData, FlatData.Count };
            }
            else
            {
                return SelfReferenceData.GetTree();
            }
        }

        private void AppendChildren(List<SelfReferenceData> ChildRecords, SelfReferenceData ParentItem, Dictionary<string, List<SelfReferenceData>> GroupData)
        {
            var queryString = Request.Query;
            string TaskId = ParentItem.TaskID.ToString();
            if (queryString.Keys.Contains("$orderby"))
            {
                StringValues srt;
                queryString.TryGetValue("$orderby", out srt);
                srt = srt.ToString().Replace("desc", "descending");
                List<SelfReferenceData> SortedChildRecords = SortingExtend.Sort(ChildRecords.AsQueryable(), srt).ToList();
                var index = FlatData.IndexOf(ParentItem);
                foreach (var Child in SortedChildRecords)
                {
                    string ParentId = Child.ParentID.ToString();
                    if (TaskId == ParentId)
                    {
                        if (FlatData.IndexOf(Child) == -1)
                            ((IList)FlatData).Insert(++index, Child);
                        if (GroupData.ContainsKey(Child.TaskID.ToString()))
                        {
                            var DeepChildRecords = GroupData[Child.TaskID.ToString()];
                            if (DeepChildRecords?.Count > 0)
                                AppendChildren(DeepChildRecords, Child, GroupData);
                        }
                    }
                }
            }
            else
            {
                var index = FlatData.IndexOf(ParentItem);
                foreach (var Child in ChildRecords)
                {
                    string ParentId = Child.ParentID.ToString();
                    if (TaskId == ParentId)
                    {
                        if (FlatData.IndexOf(Child) == -1)
                            ((IList)FlatData).Insert(++index, Child);
                        if (GroupData.ContainsKey(Child.TaskID.ToString()))
                        {
                            var DeepChildRecords = GroupData[Child.TaskID.ToString()];
                            if (DeepChildRecords?.Count > 0)
                                AppendChildren(DeepChildRecords, Child, GroupData);
                        }
                    }
                }
            }
        }

    }
}

Sending additional parameters to the Rest Web Services

To add a custom parameter to the data request, use the addParams method of Query. Assign the Query object with additional parameters to the tree grid Query property.

Copied to clipboard
@using Syncfusion.Blazor.TreeGrid;
@using Syncfusion.Blazor.Data;

<SfTreeGrid IdMapping="TaskID" TValue="BusinessObject" ParentIdMapping="ParentItem" HasChildMapping="isParent" Query=@TreeGridQuery AllowPaging="true" TreeColumnIndex="1">
<SfDataManager Url="https://ej2services.syncfusion.com/production/web-services/api/SelfReferenceData" CrossDomain="true" Adaptor="Syncfusion.Blazor.Adaptors.WebApiAdaptor"></SfDataManager>
<TreeGridColumns>
    <TreeGridColumn Field="TaskID" HeaderText="Task ID" Width="80" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="160"></TreeGridColumn>
    <TreeGridColumn Field="Duration" HeaderText="Duration" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Progress" HeaderText="Progress" Width="100" TextAlign="Syncfusion.Blazor.Grids.TextAlign.Right"></TreeGridColumn>
    <TreeGridColumn Field="Priority" HeaderText="Priority" Width="80"></TreeGridColumn>
</TreeGridColumns>
</SfTreeGrid>
@code{
public string ParamValue = "true";
public Query TreeGridQuery { get; set; }

protected override void  OnInitialized()
{
    TreeGridQuery = new Query().AddParams("ej2treegrid", ParamValue);
}
 public class BusinessObject
{
    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 double? Duration { get; set; }
    public int? ParentID { get; set; }
    public bool? isParent { get; set; }
    public bool? Approved { get; set; }
    public int? ParentItem { get; set; }
}
}

Entity Framework

You need to follow the below steps to consume data from the Entity Framework in the Tree Grid component.

Create DBContext class

The first step is to create a DBContext class called TasksContext to connect to a Microsoft SQL Server database.

Copied to clipboard
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace TreeGridWebApiEFSample.Shared.DataAccess
{
public class TasksContext: DbContext
{
    public virtual DbSet<Shared.Models.Task> Tasks { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer(@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\Documentation\TreeGridWebApiEFSample\TreeGridWebApiEFSample\Shared\App_Data\TreeGridDB.mdf;Integrated Security=True;Connect Timeout=30");
        }
    }
}
}

Create data access layer to perform data operation

Now you need to create a class named TasksDataAccessLayer, which act as data access layer for retrieving the records and also insert, update and delete the records from the database table.

Copied to clipboard
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TreeGridWebApiEFSample.Shared.Models;
using Microsoft.EntityFrameworkCore;

namespace TreeGridWebApiEFSample.Shared.DataAccess
{
public class TasksDataAccessLayer
{
    TasksContext treedb = new TasksContext();

    //To Get all Task details
    public IEnumerable<Shared.Models.Task> GetAllRecords()
    {
        try
        {
            return treedb.Tasks.ToList();
        }
        catch
        {
            throw;
        }
    }
}
}

Creating Web API Controller

A Web API Controller has to be created which allows Tree Grid directly to consume data from the Entity framework.

Copied to clipboard
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using TreeGridWebApiEFSample.Shared.Models;
using TreeGridWebApiEFSample.Shared.DataAccess;
using Microsoft.Extensions.Primitives;
using System.Web;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json.Linq;


namespace TreeGridWebApiEFSample.Controllers
{
[Route("api/[controller]")]
[ApiController]

public class TreeGridController : ControllerBase
{
    TasksDataAccessLayer db = new TasksDataAccessLayer();

    // GET: api/<TreeGridController>
    [HttpGet]
    public object Get()
    {
        var queryString = Request.Query;
        IQueryable<TreeGridWebApiEFSample.Shared.Models.Task> data1 = db.GetAllRecords().AsQueryable();
        if (queryString.Keys.Contains("$filter") && !queryString.Keys.Contains("$top"))
        {
            StringValues filter;
            queryString.TryGetValue("$filter", out filter);
            int fltr = Int32.Parse(filter[0].ToString().Split("eq")[1]);
            data1 = data1.Where(f => f.ParentID == fltr).AsQueryable();
            return new { Items = data1, Count = data1.Count() };
        }
        if (queryString.Keys.Contains("$select"))
        {
            data1 = (from ord in data1
                     select new TreeGridWebApiEFSample.Shared.Models.Task
                     {
                         ParentID = ord.ParentID
                     }
                    );
            return data1;
        }

        data1 = data1.Where(p => p.ParentID == null);
        var count = data1.Count();

        if (queryString.Keys.Contains("$inlinecount"))
        {
            StringValues Skip;
            StringValues Take;
            int skip = (queryString.TryGetValue("$skip", out Skip)) ? Convert.ToInt32(Skip[0]) : 0;
            int top = (queryString.TryGetValue("$top", out Take)) ? Convert.ToInt32(Take[0]) : data1.Count();
            return new { Items = data1.Skip(skip).Take(top), Count = count };
        }
        else
        {
            return data1;
        }
    }
}
}

Configure Tree Grid component using Web API adaptor

Now you can configure the Tree Grid using the ‘SfDataManager’ to interact with the created Web API and consume the data appropriately. To interact with web api, you need to use WebApiAdaptor.

Copied to clipboard
@using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.Data
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.TreeGrid
@using Shared.Models

<SfTreeGrid TValue="Shared.Models.Task"  @ref="treeGrid" IdMapping="TaskID" AllowPaging="true"
            ParentIdMapping="ParentID" HasChildMapping="IsParent"
            TreeColumnIndex="0">
    <SfDataManager Url="api/TreeGrid" Adaptor="Adaptors.WebApiAdaptor" CrossDomain="true"></SfDataManager>
    <TreeGridColumns>
        <TreeGridColumn Field="TaskID" HeaderText="Task ID" Width="80" IsPrimaryKey="true" Type=ColumnType.Number></TreeGridColumn>
        <TreeGridColumn Field="TaskName" HeaderText="Task Name" Width="160" Type=ColumnType.String></TreeGridColumn>
        <TreeGridColumn Field="Duration" HeaderText="Duration" Width="160" Type=ColumnType.Number></TreeGridColumn>
        <TreeGridColumn Field="Progress" HeaderText="Progress" Width="160" Type=ColumnType.Number></TreeGridColumn>

    </TreeGridColumns>
</SfTreeGrid>

@code{

SfTreeGrid<Shared.Models.Task> treeGrid { get; set; }

}

To perform Tree Grid CRUD operation using Entity Framework. You can refer here.

You can find the fully working sample here.