Dynamically create a treeview
Asked Answered
T

2

6

I am trying to create a treeview dynamically using c# and asp.net.

I have created a lazy load treeview using the populate ondemand attribute.

>  <asp:TreeView ID="treeView1"  runat="server" 
>              OnTreeNodePopulate="treeview1_TreeNodePopulate"></asp:TreeView>

Behind code I have loaded my data but initially I populate the parent nodes. What I want to achieve is when i click on parent node I then do a postback and then populate its child and then again populate its child's and so now. I have thousands of data so i dont want all data to be populated due to performance. So thats the reason why I only want to populate the node childs based on selected node. See example below:

>Peter
    - - >user1
    - - >user2
    - - >user3
       - - >userPassword
       - - >userId
>john
>david
>Jack
    - - >user1
    - - >user2
       - - >userpassword
       - - >userId
       - - >Permissions
>Laura 
    - - > admin
    - - > permissions
       -- > user1
       -- > user2
         - - >userpassword
             - - >userId
             - - >Permissions           
>...
>...
>...

As you can see there can be multiple parent nodes and multiple layers. These will be populated dynically based on what i pass in to DB. Everytime i click on node it will expand the node and populate its child using postback and then when you click on its child again it will do a postback and populate its child again etc. So i wanted help on how to create a dynamic treeview.

c# :

private void LoadTreeview()
{
 //Load data
 // Get data from DB.
 //loop through the list and build its parent nodes.
  foreach (var dxm in list)
  {
                TreeNode tnParent = CheckNodeExist(dxm.Node); //I check to see if exists.
                if (tnParent== null)
                {
                    TreeNode tn = new TreeNode();
                    tn.Text = dxm.Node;
                    tn.Value = dxm.Id.ToString();
                    tn.SelectAction = TreeNodeSelectAction.None;
                    tn.Collapse();
                    treeView1.Nodes.Add(tn);
                    tn.PopulateOnDemand = true; //lazy load
                    tnParent= tn;
                }

}

This method above is called on page load.

On TreeNodePopulateEvent: (when a node is clicked on)

protected void treeview1_TreeNodePopulate(object sender, TreeNodeEventArgs e)
        {
            ICollection<ITEMS> list = new Collection<ITEMS>();           

            list = GetData(e.Node.Text); //pass in the node you have selected  this will go and check in DB if the node does have any child nodes. If so will return with child nodes.

            foreach (var dxm in list)
            {

                TreeNode tnChild = CheckNodeExist(dxm.Node);
                if (tnChild == null)
                {
                    TreeNode tn = new TreeNode();
                    tn.Text = dxm.Node;
                    tn.Value = dxm.Id.ToString();
                    tn.SelectAction = TreeNodeSelectAction.None;
                    tn.Collapse();

                    tn.PopulateOnDemand = true;
                    tnChild = tn;
                    tnChild.ChildNodes.Add(tnChild);                  

                }
            }
        }
Tootsy answered 1/2, 2012 at 13:35 Comment(0)
V
6

I believe you are looking for the SelectedNodeChanged event. You should be able to load your child nodes in this event. Basically this event will be fired everytime you select a node by clicking on it.

Your aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div id="div1" runat="server">

    </div>

    <asp:TreeView ID="TreeView1" runat="server" 
        onselectednodechanged="TreeView1_SelectedNodeChanged">

    </asp:TreeView>

    </form>
</body>
</html>

Your codebehind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            TreeView1.Nodes.Add(new TreeNode("Node1"));
            TreeView1.Nodes[0].ChildNodes.Add(new TreeNode("ChildNode"));
        }

    }


    protected void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
    {
        Response.Write(TreeView1.SelectedNode.Text);
    }
}
Velutinous answered 1/2, 2012 at 13:45 Comment(13)
Thanks.. how do i append to the existing treeview?Tootsy
btw, "LinksTreeView" you would replace with the ID of your treeview, I copied and pasted from some old code and that was the ID that was used on my particular example.Velutinous
Its not firing the event when i click on node?? <asp:TreeView ID="treeView1" runat="server" OnSelectedNodeChanged="Select_Change"></asp:TreeView> protected void Select_Change(object sender, EventArgs e) {}Tootsy
Okay try it this way, go to the design view of your page that contains the treeview and select the treeview control. Then go to your properties tab, the properties tab should contain your treeview properties. At the top, there should be a lightning bold icon, click that icon. From the list below select "SelectedNodeChanged" and double click it. That should take you to your codebehind. Then try the code I posted above for getting the selected node text. I just tried this in a test project and it worked perfectlyVelutinous
yeah tried that and no luck <asp:TreeView ID="treeView1" runat="server" onselectednodechanged="treeView1_SelectedNodeChanged" ></asp:TreeView> protected void treeView1_SelectedNodeChanged(object sender, EventArgs e) { } I put breakpoint on this event and did not do anything?Tootsy
Hmmm that's very odd, should be working. Can you do a test by creating a new blank page with only a treeview on it and try it that way? This should be working. One thing, make sure any treeview code you have in page_load is surrounded by an if statement if(!Page.IsPostBack){}Velutinous
yes i have created a blank page.. and did if (!Page.IsPostBack) { LoadTreeview(); }Tootsy
can you post the complete code for the aspx and the aspx.cs (on your blank page)? This should be working.Velutinous
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="Test.WebForm1" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:TreeView ID="treeView1" runat="server" onselectednodechanged="treeView1_SelectedNodeChanged" ></asp:TreeView> </div> </form> </body> </html>Tootsy
namespace Test.Web { public partial class WebForm1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { LoadTreeview(); }}}} private void LoadTreeview() { } protected void treeView1_SelectedNodeChanged(object sender, EventArgs e) {}}}Tootsy
within in loadTreeview method this method just gets the data and populates the treeview. I think other ppl have the same issue with this SelectnodeChanged Event.Tootsy
I just updated my answer to reflect exactly what I have in my test sample that is working.Velutinous
sorry its sorted now.. what i did was used OnTreeNodePopulate event instead. Within this event i used the same logic that i was going to use on selectednodechange event. I then made treeview1.selectedNode = true in this event because i knew which node was selected by using the arguement. And this worked. :-) Thank you for your help and time. I can explain further if you want..Tootsy
S
0

Maybe this example will help you here i am create user tree like structure in .NET core mvc using baisc recursion.

here i'm using sql server to store the user data and each node/user is identified by the username. Each node is the indudival user. The login user will show on the top and there sub-users on the bottom forming a tree like structure with leftMember/leftNode and rightMember/rightNode.

Model Class :

public class UserModel
 {
     [Key]
     public int userId { get; set; }
     [Required]
     public string firstName { get; set; }
     [Required]
     public string lastName { get; set; }
     [Required]
     public string userName { get; set; }
     [Required]
     public string password { get; set; }
     public string leftMember { get; set; } = "";
     public string rightMember { get; set; } = "";
 }

User Login Auth :

[HttpPost]
public async Task<IActionResult> Auth(string username, string password)
{
    
    var findingFeni = context.User.Where(n => n.userName == username && n.password == password).FirstOrDefault();
    
    if(findingFeni == null)
    { 
        return Content("user or password is incorrect");
    }

    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, username)
    };

    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

    var authProperties = new AuthenticationProperties
    {
         
    };

    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
        new ClaimsPrincipal(claimsIdentity), authProperties);
     
    return RedirectToAction("Index");
      
}

Adding Left & Right member/node :

public async Task<IActionResult> addMyLeftMember(int userId)
{ 
    TempData["LeftMemberUserId"] = userId;
    return RedirectToAction("RegisterLeftMember");
}

public async Task<IActionResult> addMyRightMember(int userId)
{
    TempData["RightMemberUserId"] = userId;
    return RedirectToAction("RegisterRightMember");
}

public async Task<IActionResult> AddMemberLeft(UserModel userModel)
{

    UserModel usr = context.User.Where(n => n.userName == userModel.userName).FirstOrDefault();

    if(usr != null)
    {
        return Content("user already exist");
    }

    int userID = int.Parse(TempData["LeftMemberUserId"].ToString());
    var findingDaddy = context.User.Where(n => n.userId == userID).FirstOrDefault();
     

    findingDaddy.leftMember = userModel.userName;

    context.User.Add(userModel);
    await context.SaveChangesAsync();

    return RedirectToAction("Index");
}

public async Task<IActionResult> AddMemberRight(UserModel userModel)
{

    UserModel usr = context.User.Where(n => n.userName == userModel.userName).FirstOrDefault();

    if (usr != null)
    {
        return Content("user already exist");
    }

    int userID = int.Parse(TempData["RightMemberUserId"].ToString());
    var findingDaddy = context.User.Where(n => n.userId == userID).FirstOrDefault();

    findingDaddy.rightMember = userModel.userName;

    context.User.Add(userModel);
    await context.SaveChangesAsync();

    return RedirectToAction("Index");
}

fetching user data in index i'm fetching all users data but you can fetch only the login user data that will do the work.

public IActionResult Index()
 { 
     List<UserModel> users = context.User.ToList();
      
     string name = User.Identity.Name;

     if(name == null || name.Equals(""))
     {
         name = "admin";
     }
      
     List<UserModel> newUserList = users.Where(user => String.Compare(user.userName, User.Identity.Name) >= 0).ToList();
     return View(newUserList);
      
 }

Index Page :

@inject TASK_1._1.Context.ApplicationDbContext context
@model List<UserModel> 
@{
    ViewData["Title"] = "Home Page"; 
}
   
<div class="text-center">
    @if (Model != null && Model.Count() > 0)
    {  
        <table border="1" class="text-center">  
            @foreach (var user in Model)
            { 
                @Html.Partial("_UserNodeView", user)
                break;
            }
        </table> 
    }
</div>  

View :

@inject TASK_1._1.Context.ApplicationDbContext context
@model UserModel
@*
     
*@
@{
}

<table border="1" class="text-center">
    <a> @Model.userName </a>
        <tr>
            <td>
            @if (Model.leftMember.Equals(""))
                {
                    <div>
                        <form asp-controller="Home" asp-action="AddMyLeftMember" method="post">
                        <button class="btn btn-primary" type="submit" asp-action="AddMyLeftMember" asp-route-userId="@Model.userId"> Left </button>
                        </form>
                    </div>
                }
                else
                {
                    var u = context.User.Where(n => n.userName == Model.leftMember).FirstOrDefault();
                    @Html.Partial("_UserNodeView", u)
                }
            </td>

            <td>
            @if (Model.rightMember.Equals(""))
                {
                    <div>
                        <form asp-controller="Home" asp-action="AddMyRightMember" method="post">
                        <button class="btn btn-primary" type="submit" asp-action="AddMyRightMember" asp-route-userId="@Model.userId"> Right </button>
                        </form>
                    </div>
                }
                else
                {
                    var u = context.User.Where(n => n.userName == Model.rightMember).FirstOrDefault();
                    @Html.Partial("_UserNodeView", u)
                }
            </td>
        </tr>
    
</table> 
Sensuality answered 30/12, 2023 at 15:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.