I am trying to create my own treeview binary tree where it shows folders and children / parents for certain folders.
I have a big list of folders then I have it in a custom object the Index, Parent Name, Children bool, and display name on the tree.
I can create the tree but when it creates it all the children are under the first node and not under the correct ones.
I see that treenode has level and parent if I could set those then this would be easy but I see they are readonly so I’m kinda stuck so far…
List<TreeNodeEnd> lstTreeNod = new List<TreeNodeEnd>();
Dictionary<int, TreeNode> valuePairs = new Dictionary<int, TreeNode>();
foreach (var node in lstTreeNod)
{
TreeNodeCollection items;
TreeNode treeNode;
if (node.TreeIndex == 0)
{
//node.DisplayName = "PDM Vault";
//TreeNode root2 = new TreeNode("PDM Vault", 3, 3, items);
//root.Name = "PDM Vault";
items = treeView1.Nodes;
//items = items.Add(node.DisplayName);
//treeView1.Nodes
}
else //in this ELSE DETERMINE ABOUT FATHER & CHILDREN EQUALS AND NOT NULL
{ // ValuePairs = Final Tree ?
//items = valuePairs[node.TreeIndex - 1].Nodes;
items = valuePairs[node.TreeIndex].Nodes;
TreeNode treeNode = items.Add(node.DisplayName);
}
TreeNode treeNode = items.Add(node.DisplayName);
if (valuePairs.ContainsKey(node.TreeIndex))
{
if (node.HasChildren == true)
valuePairs[node.TreeIndex] = treeNode;
}
else
{
valuePairs.Add(node.TreeIndex, treeNode);
}
}
public class TreeNodeEnd
{
public string DisplayName { get; set; }
public int TreeIndex { get; set; }
public bool HasChildren { get; set; }
public string Father { get; set; }
}
Related
I need to build a hierarchy and I am using a dictionary.
I read strings randomly when I am trying to build this
and they have this format:
address.city.streetname.housenumber
address.areacode
address.city.streetname.coAddress
I have a problem figuring out how to populate the entire hierarchy
This is what I have done:
public class JsonElement
{
public string parent { get; set; }
public string name { get; set; }
public List<JsonElement> childrenJsonElements { get; set; }
}
var dictionaryHierarchy = new Dictionary<string, JsonElement>();
List<string> stringList = new List<string>()
{ "address.city.streetname.housenumber",
"address.areacode",
"address.city.streetname.coAddress"};
foreach(string element in stringList)
{
string[] tagsStringArray = element.Split('.');
if (!dictionaryHierarchy.ContainsKey(tagsStringArray[0]))
{
dictionaryHierarchy.Add(tagsStringArray[0], new JsonElement());
}
dictionaryHierarchy = AddElementsToHierarchy();
}
private static Dictionary<string, JsonElement> AddElementsToHierarchy(Dictionary<string,
JsonElement> dictionaryHierarchy, string element)
{
JsonElement jsonElement = new JsonElement();
string[] tagsStringArray = element.Split('.');
if (tagsStringArray.Length < 2)
{
return dictionaryJsonHierarchy;
}
jsonElement = dictionaryHierarchy[tagsStringArray[0]];
int ix = 1;
while (ix < tagsStringArray.Length)
{
if (jsonElement.name != tagsStringArray[ix])
{
jsonElement.parent = tagsStringArray[ix-1];
jsonElement.name = tagsStringArray[ix];
}
else
{
; // This part is for adding children
}
ix++;
}
return dictionaryHierarchy;
}
You have a tree structure made up of JsonElement nodes. This structure is the only data structure you need. Let's redefine JsonElement:
public class JsonElement
{
public string Parent { get; set; }
public string Name { get; set; }
public List<JsonElement> Children { get; } = new List<JsonElement>();
}
We made the properties PascalCase. This is the usual naming convetion. The Children are a read-only property with an initializer which instantiates the list.
As suggested, we add some more examples:
var input = new[] {
"address.city.streetname.housenumber",
"address.areacode",
"address.city.streetname.coAddress",
"person.name.firstname",
"person.name.lastname"
};
Now, we have two different elements at the start of the hierarchy. To enable this scenario, we add a neutral root element with a null name.
var root = new JsonElement();
foreach (string s in input) {
AddElements(root, s.Split('.'));
}
Now, let's create the hierarchy.
Adding elements consists of walking down the tree structure by following the tags (names). If one is missing, we add it.
private static void AddElements(JsonElement node, string[] elements)
{
foreach (string element in elements) {
var child = node.Children.Find(child => child.Name == element);
if (child == null) {
child = new JsonElement {
Parent = node.Name,
Name = element
};
node.Children.Add(child);
}
node = child; // Walk down the tree
}
}
We can test the result with this recursive method:
private static void PrintChildren(JsonElement node, int level = 0)
{
string indent = new String(' ', 4 * level);
foreach (var child in node.Children) {
Console.WriteLine($"{indent}{child.Name}, Parent = {child.Parent}");
PrintChildren(child, level + 1);
}
}
Called with PrintChildren(root); it prints:
address, Parent =
city, Parent = address
streetname, Parent = city
housenumber, Parent = streetname
coAddress, Parent = streetname
areacode, Parent = address
person, Parent =
name, Parent = person
firstname, Parent = name
lastname , Parent = name
See also:
Data Structure and Algorithms - Tree
Tree (data structure)
I have hierarchy tree, each element has a list of children and so on.
This is the class:
public class HierarchyItem
{
public int? HierarchyID { get; set; }
public string label { get; set; }
public List<HierarchyItem> children { get; set; }
public int Level { get; set; }
public int ParentID { get; set; }
}
I am trying to search for all the nodes that their label contains my search term.
I already managed to get the nodes that match my search term.
In addition i created a recursion to get all the parents (until the top node) for every node that match my search term.
The problem is that in this way i get a reverse tree:
Every children has parent that has parent and so on instead of getting parent with children that has a children and so on.
Any Idea? How to act?
I am not sure it will help, but this is the relevant code.
HierarchyItem result = new HierarchyItem();
var fullHierarchies = _entities.Hierarchies.Where(p => !p.Deleted).ToList();
var hierarchiesResult = _entities.Hierarchies.Where(p => !p.Deleted && p.Name.Contains(searchTerm)).ToList();
List<HierarchyItemWithParentAsHierarchyItem> itemsWithTrees = new List<HierarchyItemWithParentAsHierarchyItem>();
var hierarchyTop = new HierarchyItemWithParentAsHierarchyItem
{
HierarchyID = null,
label = "Organization",
Code = "0",
Path = string.Empty,
Level = 0,
Parent = null
};
foreach (var item in hierarchiesResult)
{
var hierarchy = new HierarchyItemWithParentAsHierarchyItem
{
HierarchyID = item.HierarchyID,
label = item.Name,
Code = item.Code,
Path = string.Empty,
Level = item.Level.Value,
};
hierarchy.Parent.Add(GetParent(fullHierarchies, item, hierarchyTop));
itemsWithTrees.Add(hierarchy);
}
private HierarchyItemWithParentAsHierarchyItem GetParent(List<CloudEntities.Hierarchy> fullHierarchies, CloudEntities.Hierarchy item, HierarchyItemWithParentAsHierarchyItem hierarchyTop)
{
try
{
HierarchyItemWithParentAsHierarchyItem tempHierarchyItem;
CloudEntities.Hierarchy tempHierarchy = fullHierarchies.FirstOrDefault(x => x.HierarchyID == item.ParentID);
if (tempHierarchy == null)
return hierarchyTop;
else
{
tempHierarchyItem = new HierarchyItemWithParentAsHierarchyItem()
{
HierarchyID = tempHierarchy.HierarchyID,
label = tempHierarchy.Name,
Code = tempHierarchy.Code,
Path = string.Empty,
Level = tempHierarchy.Level.Value
};
tempHierarchyItem.Parent.Add(GetParent(fullHierarchies, tempHierarchy, hierarchyTop));
}
return tempHierarchyItem;
}
catch (Exception ex)
{
}
}
I have the following model
public class Node
{
public int AutoIncrementId { get; set; }
public string Text { get; set; }
public List<Node> Nodes { get; set; }
...//other propeties
}
I want to transform the data into the following model,
public class TreeView
{
public int Id {get; set;}
public string Text {get; set;}
public List<TreeView> Items {get; set;}
}
I started with the following, but then realised how am I going to know when to stop?
the variable test holds the node data
var items = test.Data.Select(x => new TreeViewItemModel
{
Id = x.AutoIncrementId.ToString(),
Text = x.Text,
Items = x.Nodes.Select(y=> new TreeViewItemModel(
{
Id = y.AutoIncrementId.ToString(),
Text = y.Text,
Items = //do I keep going?
}));
}
);
You can use recursion to do that:
public TreeView ConvertToTreeView(Node node)
{
TreeView tv = new TreeView();
tv.Id = node.AutoIncrementId;
tv.Text = node.Text;
if (node.Nodes != null && node.Nodes.Count > 0)
{
tv.Items = new List<TreeView>();
node.Nodes.ForEach(x => tv.Items.Add(ConvertToTreeView(x)));
}
return tv;
}
For clarity and simplicity, this works nicely:
public TreeView ConvertNode(Node rootNode)
{
var tree = new TreeView
{
Id = rootNode.AutoIncrementId,
Text = rootNode.Text,
Items = new List<TreeView>()
};
if (rootNode.Nodes != null)
{
foreach (var node in rootNode.Nodes)
{
tree.Items.Add(ConvertNode(node));
}
}
return tree;
}
I prefer this form.
public TreeView ConvertToTreeView(Node node)
{
return new TreeView
{
Id = node.AutoIncrementId;
Text = node.Text;
Items = node.Nodes.Select(ConvertToTreeView).ToList()
};
}
Edit: Yes Baldrick, I did :P and
public TreeView ConvertToTreeView(Node node)
{
return new TreeView
{
Id = node.AutoIncrementId;
Text = node.Text;
Items = node.Nodes != null
? node.Nodes.Select(ConvertToTreeView).ToList()
: new List<TreeView>()
};
}
Just doesn't look as nice.
I have a Node class in C# with the following properties:
public class Node
{
public int Id {get;set;}
public int? ParentId {get;set;}
public string Label {get;set;}
}
I have a TreeView control which provides the following method to create
a new node:
MyTreeView.CreateNode(key, label);
parent.Nodes.CreateNode(key, label);
If I want to add a new child node I need to use the second method otherwise the first one. Both returns an object of type TreeNode.
How would you create in C# a recursive function to populate the treeview considering that the root nodes have ParentId = null?
This is what I have done so far:
// create a list of root nodes
var roots = myList.Where(x => x.ParentId == null);
// send the roots to a recursive func
foreach(var root in roots)
{
AddNode(null,root,myList);
}
this is my recursive function:
private void AddNode(Node parent, Node current, IList<Node> items)
{
TreeNode treenode = null;
if(parent == null)
{
treenode = mytree.CreateNode(current.Id.ToString(), current.Label);
}else{
var parentnode = mytree.GetNode(parent.Id.ToString());
treenode = parentnode.Nodes.CreateNode(current.Id.ToString(), current.Label);
}
// call the recursion for the children
var children = items.Where(x => x.ParentId == current.Id);
foreach(var child in children)
{
AddNode(current, child, items);
}
}
If your tree view control is derived from System.Windows.Forms.TreeView you can replace
MyTreeView.CreateNode(key, label);
parent.Nodes.CreateNode(key, label);
with
MyTreeView.Nodes.Add(key, label);
parent.Nodes.Add(key, label);
So the call always goes to a Nodes collection which is of type TreeNodeCollection. Instead of your Node object you can now use the Nodes collection as parameter.
var roots = myList.Where(x => x.ParentId == null);
foreach (var root in roots)
{
AddNode(mytree.Nodes, root, myList);
}
private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items)
{
TreeNode treenode = nodes.Add(current.Id.ToString(), current.Label);
var children = items.Where(x => x.ParentId == current.Id);
foreach (var child in children)
{
AddNode(treenode.Nodes, child, items);
}
}
This has two benefits:
You don't need to lookup the parent each time.
You only have one call (TreeNodeCollection.Add).
However, if you can not access the TreeView.Nodes collection in the AddNode call for each root you will have to check for that at the top of the AddNode method.
var roots = myList.Where(x => x.ParentId == null);
foreach (var root in roots)
{
AddNode(null, root, myList);
}
private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items)
{
if (nodes == null)
{
nodes = myTree.Nodes;
}
...
}
Try this code:
var lookup = myList.ToLookup(n => n.ParentId.ToString());
Action<IEnumerable<TreeNode>> addChildren = null;
addChildren = tns =>
{
var query =
from tn in tns
from cn in lookup[tn.Name]
select tn.Nodes.CreateNode(cn.Id.ToString(), cn.Label);
var nodes = query.ToArray();
if (nodes.Length > 0)
{
addChildren(nodes);
}
};
addChildren(
lookup[null]
.Select(n =>
MyTreeView.CreateNode(n.Id.ToString(), n.Label)));
I couldn't fully test it, so you might need to change some of the code to make it work, but it should be fairly close.
I'd probably do something like this...
public class Node
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Label { get; set; }
public Node(int? parentId, int id, string label)
{
ParentId = parentId;
Id = id;
Label = label;
}
}
public class TreeNode : List<TreeNode>
{
public string Key { get; set; }
public string Label { get; set; }
public IEnumerable<TreeNode> Descendants
{
get
{
yield return this;
foreach (var child in this)
{
foreach (var descendant in child.Descendants)
{
yield return descendant;
}
}
}
}
public TreeNode(string key, string label)
{
Key = key;
Label = label;
}
public void CreateNode(int id, string label)
{
Add(new TreeNode(id.ToString(), label));
}
}
public class Tree
{
private TreeNode _root = new TreeNode(null, null);
public Tree(IEnumerable<Node> nodes)
{
nodes.ToList().ForEach(node => CreateNode(node.ParentId, node.Id, node.Label));
}
public void CreateNode(int? parentId, int id, string label)
{
if (parentId == null)
{
_root.CreateNode(id, label);
}
else
{
_root.Descendants.First(x => x.Key == parentId.ToString()).CreateNode(id, label);
}
}
public IEnumerable<TreeNode> Descendants => _root.Descendants;
}
Try this code:
Node{
Id, Label, List<Tree> Children
}
Tree GetTree(id){
var node=new Node();
node.Id=id;
node.Children=new List<Node>();
List<Node> children = db.Nodes.Where(x => x.ParentId==id);
foreach(child in children){
var childTree=GetTree(child.Id);
node.Children.Add(childTree);
}
return node;
}
I would like to get some suggestions on how I can build a tree out of items list in a efficient way
public class Item
{
public Item(int id, int? parentId)
{
Id = id;
ParentId = parentId;
}
public int Id { get; private set; }
public int? ParentId { get; private set; }
public List<Item> SubItems { get; set; }
}
private Item BuildATree()
{
var items = new List<Item>()
{
new Item(1, null),
new Item(2, 1),
new Item(3, 1),
new Item(4, 1),
new Item(5, 2),
new Item(6, 2),
new Item(7, 4),
new Item(8, 7),
new Item(9, 1),
};
//Build a tree out of list items
}
The result I am expecting is each item being in its parent's SubItems list
Not necessarily using the same Item class, because Ids would be redundant then
I'd use LINQ:
//Build a tree out of list items
foreach (Item item in items)
{
item.SubItems = items.Where(i => i.ParentId.Value == item.Id).ToList();
}
UPD:
To simplify moving items from one parent to another you'll need to store a reference to parent Item in every Item. Something like:
public class Item
{
public Item(int id, int? parentId)
{
Id = id;
ParentId = parentId;
}
public int Id { get; private set; }
public int? ParentId { get; private set; }
public List<Item> SubItems { get; set; }
private Item _parent;
public Item Parent
{
get { return _parent; }
set
{
if (_parent != null)
_parent.SubItems.Remove(this);
_parent = value;
if (_parent != null)
_parent.SubItems.Add(this);
}
}
}
If you implement in that way then just setting new Parent item via this property will be enough to modify both old and new parent's SubItems collections - but beware that you'll also need a bit more complex list initialization mechanism.
Solution which is efficient enough
private void RecursiveBuilder(ref Item i, IEnumerable<Item> li)
{
var item = i;
i.SubItems = (from n in li where n.ParentId == item.Id select n).ToList();
i.SubItems.ForEach(f => RecursiveBuilder(ref f, li));
}
If you don't want/have Link :
Dictionary<int,Item> dic = new Dictionary<int,Item>();
foreach(Item item in items)
{
Item parent;
if(item.ParentId!=null && dic.TryGetValue(item.ParentId, out parent))
parent.SubItems.Add(item);
else
dic.Add(item.Id, item);
}
Item root = dic[1];
I supposed that there will always be a Item with id = 1 and that's the root of the tree.
If you want to use new Class without the ids, create them instead of simply add them to their parents.