In this article, we will create dynamic Treeview in asp.net MVC from database data, which will help you link parent node with the child node and sub-child node easily. We will create a dynamic tree view menu fetched from the database, using ASP.NET MVC 5, C#, Razor and SQL Server 2012 .

Step 1: Create a project in your Visual Studio(2017 in my example), by opening Visual Studio and clicking "File"-> "New"-> "Project"

dynamic-treeview-in-aspnet-mvc-from-database-step-by-step-min

Select MVC template to generate basic home controller and other details

Step 2: Now, for example ,I have this table in my database, which we need to show in Treeview, with the following table rows

database-table-treeview-min

as you can see above we have four columns on the table, where Pid is Main parent Id, you can create this table in your database with the following script

USE [TreeviewMVC]
GO
/****** Object:  Table [dbo].[Categories]    Script Date: 12/31/2017 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Categories](
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[Name] [varchar](100) NULL,
	[Description] [varchar](100) NULL,
	[Pid] [int] NULL,
 CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
SET IDENTITY_INSERT [dbo].[Categories] ON 

INSERT [dbo].[Categories] ([ID], [Name], [Description], [Pid]) VALUES (1, N'Java', N'Java', NULL)
INSERT [dbo].[Categories] ([ID], [Name], [Description], [Pid]) VALUES (2, N'JSP', N'JSP', 1)
INSERT [dbo].[Categories] ([ID], [Name], [Description], [Pid]) VALUES (3, N'ASP.NET', N'ASP.NET', NULL)
INSERT [dbo].[Categories] ([ID], [Name], [Description], [Pid]) VALUES (4, N'ASP.NET MVC', N'ASP.NET MVC', 3)
INSERT [dbo].[Categories] ([ID], [Name], [Description], [Pid]) VALUES (5, N'Web-Forms', N'Web-Forms', 3)
INSERT [dbo].[Categories] ([ID], [Name], [Description], [Pid]) VALUES (6, N'Razor Syntax', N'Razor Syntax', 4)
SET IDENTITY_INSERT [dbo].[Categories] OFF
/****** Object:  Index [IX_Pid]    Script Date: 12/31/2017 6:39:22 PM ******/
CREATE NONCLUSTERED INDEX [IX_Pid] ON [dbo].[Categories]
(
	[Pid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Categories]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Categories_dbo.Categories_Pid] FOREIGN KEY([Pid])
REFERENCES [dbo].[Categories] ([ID])
GO
ALTER TABLE [dbo].[Categories] CHECK CONSTRAINT [FK_dbo.Categories_dbo.Categories_Pid]
GO

Step 3: Now link project with database using ADO.NET and Entity framework, right click on Models folder in Visual Studio , Select "Add" -> "ADO.NET Entity Model"/ "New Item"->"Data(Left pane)  & ADO.NET Entity Model(right pane)" -> Name it and click "Add"

treeview-create-model-entity-framework-min.png

Select "Ef designer from  database" -> Click "Next"-> "New Connection" -> Conenct to your database by entering credentials of your database and selecting database

entity-framework-min.png

After entering connecting to database and clicking "OK", Select "Yes, include the sensitive data in the connection string", click "Next", Select Ef version "Entity Framework 6.0", Click "Next", check "Tables" and click "Finish"

Ef-laststep-min.png

Step 4: Now  let's create a custom HTML helper class  to render treeview in Razor,  Add new class in "Models" folder and name it as "TreeViewHelper", and use the code below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using System.Web.WebPages;

namespace TreeviewMVC.Models
{
    public static class TreeViewHelper
    {
        /// <summary>  
        /// Create an HTML tree from a recursive collection of items  
        /// </summary>  
        public static TreeView<T> TreeView<T>(this HtmlHelper html, IEnumerable<T> items)
        {
            return new TreeView<T>(html, items);
        }
    }

    /// <summary>  
    /// Create an HTML tree from a resursive collection of items  
    /// </summary>  
    public class TreeView<T> : IHtmlString
    {
        private readonly HtmlHelper _html;
        private readonly IEnumerable<T> _items = Enumerable.Empty<T>();
        private Func<T, string> _displayProperty = item => item.ToString();
        private Func<T, IEnumerable<T>> _childrenProperty;
        private string _emptyContent = "No children";
        private IDictionary<string, object> _htmlAttributes = new Dictionary<string, object>();
        private IDictionary<string, object> _childHtmlAttributes = new Dictionary<string, object>();
        private Func<T, HelperResult> _itemTemplate;

        public TreeView(HtmlHelper html, IEnumerable<T> items)
        {
            if (html == null) throw new ArgumentNullException("html");
            _html = html;
            _items = items;
            // The ItemTemplate will default to rendering the DisplayProperty  
            _itemTemplate = item => new HelperResult(writer => writer.Write(_displayProperty(item)));
        }

        /// <summary>  
        /// The property which will display the text rendered for each item  
        /// </summary>  
        public TreeView<T> ItemText(Func<T, string> selector)
        {
            if (selector == null) throw new ArgumentNullException("selector");
            _displayProperty = selector;
            return this;
        }


        /// <summary>  
        /// The template used to render each item in the tree view  
        /// </summary>  
        public TreeView<T> ItemTemplate(Func<T, HelperResult> itemTemplate)
        {
            if (itemTemplate == null) throw new ArgumentNullException("itemTemplate");
            _itemTemplate = itemTemplate;
            return this;
        }


        /// <summary>  
        /// The property which returns the children items  
        /// </summary>  
        public TreeView<T> Children(Func<T, IEnumerable<T>> selector)
        {
            //  if (selector == null) //throw new ArgumentNullException("selector");  
            _childrenProperty = selector;
            return this;
        }

        /// <summary>  
        /// Content displayed if the list is empty  
        /// </summary>  
        public TreeView<T> EmptyContent(string emptyContent)
        {
            if (emptyContent == null) throw new ArgumentNullException("emptyContent");
            _emptyContent = emptyContent;
            return this;
        }

        /// <summary>  
        /// HTML attributes appended to the root ul node  
        /// </summary>  
        public TreeView<T> HtmlAttributes(object htmlAttributes)
        {
            HtmlAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
            return this;
        }

        /// <summary>  
        /// HTML attributes appended to the root ul node  
        /// </summary>  
        public TreeView<T> HtmlAttributes(IDictionary<string, object> htmlAttributes)
        {
            if (htmlAttributes == null) throw new ArgumentNullException("htmlAttributes");
            _htmlAttributes = htmlAttributes;
            return this;
        }

        /// <summary>  
        /// HTML attributes appended to the children items  
        /// </summary>  
        public TreeView<T> ChildrenHtmlAttributes(object htmlAttributes)
        {
            ChildrenHtmlAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
            return this;
        }

        /// <summary>  
        /// HTML attributes appended to the children items  
        /// </summary>  
        public TreeView<T> ChildrenHtmlAttributes(IDictionary<string, object> htmlAttributes)
        {
            if (htmlAttributes == null) throw new ArgumentNullException("htmlAttributes");
            _childHtmlAttributes = htmlAttributes;
            return this;
        }

        public string ToHtmlString()
        {
            return ToString();
        }

        public void Render()
        {
            var writer = _html.ViewContext.Writer;
            using (var textWriter = new HtmlTextWriter(writer))
            {
                textWriter.Write(ToString());
            }
        }

        private void ValidateSettings()
        {
            if (_childrenProperty == null)
            {
                return;
            }
        }


        public override string ToString()
        {
            ValidateSettings();
            var listItems = new List<T>();
            if (_items != null)
            {
                listItems = _items.ToList();
            }


            var ul = new TagBuilder("ul");
            ul.MergeAttributes(_htmlAttributes);
            var li = new TagBuilder("li")
            {
                InnerHtml = _emptyContent
            };
            li.MergeAttribute("id", "-1");

            if (listItems.Count > 0)
            {
                var innerUl = new TagBuilder("ul");
                innerUl.MergeAttributes(_childHtmlAttributes);

                foreach (var item in listItems)
                {
                    BuildNestedTag(innerUl, item, _childrenProperty);
                }
                li.InnerHtml += innerUl.ToString();
            }
            ul.InnerHtml += li.ToString();

            return ul.ToString();
        }

        private void AppendChildren(TagBuilder parentTag, T parentItem, Func<T, IEnumerable<T>> childrenProperty)
        {
            //  
            if (childrenProperty == null)
            {
                return;
            }
            var children = childrenProperty(parentItem).ToList();
            if (!children.Any())
            {
                return;
            }

            var innerUl = new TagBuilder("ul");
            innerUl.MergeAttributes(_childHtmlAttributes);

            foreach (var item in children)
            {
                BuildNestedTag(innerUl, item, childrenProperty);
            }

            parentTag.InnerHtml += innerUl.ToString();
        }

        private void BuildNestedTag(TagBuilder parentTag, T parentItem, Func<T, IEnumerable<T>> childrenProperty)
        {
            var li = GetLi(parentItem);
            parentTag.InnerHtml += li.ToString(TagRenderMode.StartTag);
            AppendChildren(li, parentItem, childrenProperty);
            parentTag.InnerHtml += li.InnerHtml + li.ToString(TagRenderMode.EndTag);
        }

        private TagBuilder GetLi(T item)
        {
            var li = new TagBuilder("li")
            {
                InnerHtml = _itemTemplate(item).ToHtmlString()
            };
            Type myType = item.GetType();
            IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
            foreach (PropertyInfo prop in props)
            {
                if (prop.Name.ToLower() == "id")
                    li.MergeAttribute("id", prop.GetValue(item, null).ToString());
                // Do something with propValue  
                if (prop.Name.ToLower() == "sortorder")
                    li.MergeAttribute("priority", prop.GetValue(item, null).ToString());
            }
            return li;
        }
    }
}

the above helps us to create recursive <ul><li> HTML code based on Pid .

Step 5: Now we need to add jstree in our project which will help us convert ul/li html into tree view, so from the top menu, click on Tools -> NuGet Package Manager -> Manage NuGet packages for solution.

Choose "Browse" tab, then type jsTree,

Then, hit on Install button to download JSTree and include it in your project.
 
jstree-install-using-nuget-min
 
Step 6:  Now, let's add the below code in your HomeController to get data from database
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TreeviewMVC.Models;


namespace TreeviewMVC.Controllers
{
    public class HomeController : Controller
    {
        TreeviewMVCEntities context = new TreeviewMVCEntities();
        public ActionResult Index()
        {
           
            return View(context.Categories.Where(x => !x.Pid.HasValue).ToList());
        }

       
    }
}

last step go to the Index view and add the required html code to render tree view using jqTree and HTMLhelper which we created earlier

@model IEnumerable<TreeviewMVC.Models.Category>
@using System.Web.UI.WebControls
@using TreeviewMVC.Models;

<h2>TreeView</h2>
<link href="~/Content/jsTree/themes/default/style.min.css" rel="stylesheet" />
<div class="form-body">
    <div id="jstree">
        @(Html.TreeView(Model)
                              .EmptyContent("root")
                              .Children(m => m.Categories1)
                              .HtmlAttributes(new { id = "tree" })
                          .ChildrenHtmlAttributes(new { @class = "subItem" })
                              .ItemText(m => m.Name)
                              .ItemTemplate(
            @<text>
                <a href="@item.Description" desc="@item.Description">@item.Name</a>
            </text>)
        )
    </div>
</div>
@section scripts
    {
    <script src="~/Scripts/jsTree3/jstree.min.js"></script>
    <script>

            $(function () {
                var selectedData;
                $('#jstree').jstree({
                    "core": {
                        "multiple": true,
                        "check_callback": false,
                        'themes': {
                            "responsive": true,
                            'variant': 'larg',
                            'stripes': false,
                            'dots': false
                        }
                    },
                    "types": {
                        "default": {
                            "icon": "fa fa-folder icon-state-warning icon-lg"
                        },
                        "file": {
                            "icon": "fa fa-file icon-state-warning icon-lg"
                        }
                    },
                    "plugins": ["dnd", "state", "types", "sort", "checkbox"]
                });
            });
    </script>
}   

After completing the above steps run your prjoect and output will be as below

 
treeview-aspnet-mvc-database-min.png
That's we have now created dynamic Treeview in MVC using jqTree and Custom HTML helper.