Transfer stringlist into treeview - c#

I have a String List with items like this
"Root"
"Root/Item1"
"Root/Item2"
"Root/Item3/SubItem1"
"Root/Item3/SubItem2"
"Root/Item4/SubItem1"
"AnotherRoot"
How do I transfer this stringlist into a treeview ?

You can split each item into it's substrings. Then via recursion look for each item, if the parent exists add to it, and if the parent doesn't exists create it.
If you can't see how to do it, i`ll post you a sample code
Sample Code
public void AddItem(TreeView treeControl, TreeNode parent, string item)
{
TreeNodeCollection nodesRef = (parent != null) ? parent.Nodes : treeControl.Nodes;
string currentNodeName;
if (-1 == item.IndexOf('/')) currentNodeName = item;
else currentNodeName = item.Substring(0, item.IndexOf('/'));
if (nodesRef.ContainsKey(currentNodeName))
{
AddItem(treeControl, nodesRef[currentNodeName], item.Substring(currentNodeName.Length+1));
}
else
{
TreeNode newItem = nodesRef.Add(currentNodeName, currentNodeName);
if (item.Length > currentNodeName.Length)
{
AddItem(treeControl, newItem, item.Substring(item.IndexOf('/', currentNodeName.Length) + 1));
}
}
}
And the caller example:
string[] stringArr = {
"Root",
"Root/Item1",
"Root/Item2",
"Root/Item3/SubItem1",
"Root/Item3/SubItem2",
"Root/Item4/SubItem1",
"AnotherRoot"
};
foreach (string item in stringArr)
{
AddItem(treeView1, null, item);
}

One way is to iterate the items split the item and push them on a list and if the parent doesn't match pop an item from the list until the stack is empty or you have a match.

You can use this code:
private void button1_Click(object sender, EventArgs e) {
List<String> paths = new List<String> {
"Root", "Root/Item1", "Root/Item2", "Root/Item3/SubItem1",
"Root/Item3/SubItem2", "Root/Item4/SubItem1", "AnotherRoot"
};
List<TreeNode> nodeCollection = new List<TreeNode>();
foreach (var path in paths) {
AddPath(nodeCollection, path);
}
treeView1.Nodes.Clear();
treeView1.Nodes.AddRange(nodeCollection.ToArray());
}
public void AddPath(List<TreeNode> collection, String path) {
LinkedList<String> pathToBeAdded = new LinkedList<String>(path.Split(new String[] { #"/" }, StringSplitOptions.RemoveEmptyEntries));
if (pathToBeAdded.Count == 0) {
return;
}
String rootPath = pathToBeAdded.First.Value;
TreeNode root = collection.FirstOrDefault(n => n.Text.Equals(rootPath));
if (root == null) {
root = new TreeNode(rootPath);
collection.Add(root);
}
pathToBeAdded.RemoveFirst();
AddPath(root, pathToBeAdded);
}
public void AddPath(TreeNode rootNode, LinkedList<String> pathToBeAdded) {
if (pathToBeAdded.Count == 0) {
return;
}
String part = pathToBeAdded.First.Value;
TreeNode subNode = null;
if (!rootNode.Nodes.ContainsKey(part)) {
subNode = rootNode.Nodes.Add(part, part);
} else {
subNode = rootNode.Nodes[part];
}
pathToBeAdded.RemoveFirst();
AddPath(subNode, pathToBeAdded);
}
Hope this helps.
Ricardo Lacerda Castelo Branco

Related

Some problems about JSON data to C# Winforms TreeView

Firstly, I read heaps of topics about JSON to TreeView on the Stackoverflow. After this, I create a JSON data like this:
{
"Cars": {
"Audi": [{
"A6 2.0 TDI quatro 2018 Red": ["S-Line", "17 inch rim", "Full sport packet"],
"A5 1.6 TFSI 2018 Blue": ["Desing packet", "Sunroof"]
}],
"Mercedes-Benz": [{
"E220d AMG 2018 white": ["Glass ceiling", "Vacuum doors", "Navigation"],
"E220d Exclusive Black 2018 Blue": ["Power seats", "Start & Stop"]
}]
}
}
Here is the C# code content:
private void Form1_Load(object sender, EventArgs e)
{
try
{
treeView1.Nodes.Clear();
var json = File.ReadAllText(Uz.path + #"cars.json");
var obj = JObject.Parse(json);
var parent = Json2Tree(obj);
treeView1.Nodes.Add(parent);
treeView1.ExpandAll();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, #"ERROR");
}
}
private static TreeNode Json2Tree(JObject obj)
{
//create the parent node
var parent = new TreeNode();
//loop through the obj. all token should be pair<key, value>
foreach (var token in obj)
{
//change the display Content of the parent
parent.Text = token.Key;
//create the child node
var child = new TreeNode();
child.Text = token.Key;
//check if the value is of type obj recall the method
if (token.Value.Type.ToString() == "Object")
{
// child.Text = token.Key.ToString();
//create a new JObject using the the Token.value
var o = (JObject)token.Value;
//recall the method
child = Json2Tree(o);
//add the child to the parentNode
parent.Nodes.Add(child);
}
//if type is of array
else if (token.Value.Type.ToString() == "Array")
{
int ix = -1;
// child.Text = token.Key.ToString();
//loop though the array
foreach (var itm in token.Value)
{
//check if value is an Array of objects
if (itm.Type.ToString() == "Object")
{
//child.Text = token.Key.ToString();
//call back the method
ix++;
var o = (JObject)itm;
var objTN = Json2Tree(o);
//objTN.Text = token.Key + "[" + ix + "]";
child.Nodes.Add(objTN);
//parent.Nodes.Add(child);
}
//regular array string, int, etc
else if (itm.Type.ToString() == "Array")
{
ix++;
var dataArray = new TreeNode();
foreach (var data in itm)
{
//dataArray.Text = token.Key + "[" + ix + "]";
dataArray.Nodes.Add(data.ToString());
}
child.Nodes.Add(dataArray);
}
else
{
child.Nodes.Add(itm.ToString());
}
}
parent.Nodes.Add(child);
}
else
{
//if token.Value is not nested
// child.Text = token.Key.ToString();
//change the value into N/A if value == null or an empty string
child.Nodes.Add(token.Value.ToString() == "" ? "N/A" : token.Value.ToString());
parent.Nodes.Add(child);
}
}
return parent;
}
when I run the code, the screenshot looks like this:
But marked as 1, 2 and 3 are should not be shown. It must be like this:
Although I worked 3 days, I did not succeed.
In JsonTreeView project, it show like this:
using System.Windows.Forms;
using Newtonsoft.Json.Linq;
namespace JsonTreeView
{
public static class JsonToTreeView
{
public static void Json2Tree(this TreeView treeView, string json, string group_name)
{
if (string.IsNullOrWhiteSpace(json))
{
return;
}
var obj = JObject.Parse(json);
AddObjectNodes(obj, group_name, treeView.Nodes);
}
public static void AddObjectNodes(JObject obj, string name, TreeNodeCollection parent)
{
var node = new TreeNode(name);
parent.Add(node);
foreach (var property in obj.Properties())
{
AddTokenNodes(property.Value, property.Name, node.Nodes);
}
}
private static void AddArrayNodes(JArray array, string name, TreeNodeCollection parent)
{
var node = new TreeNode(name);
parent.Add(node);
for (var i = 0; i < array.Count; i++)
{
AddTokenNodes(array[i], $"[{i}]", node.Nodes);
}
}
private static void AddTokenNodes(JToken token, string name, TreeNodeCollection parent)
{
switch (token)
{
case JValue _:
parent.Add(new TreeNode($"{((JValue) token).Value}"));
break;
case JArray _:
AddArrayNodes((JArray)token, name, parent);
break;
case JObject _:
AddObjectNodes((JObject)token, name, parent);
break;
}
}
}
}

Populate TreeView with data from a DataGridView in c#

I'm trying to populate a TreeView with data from a DataGridView, but I can not.
The DataGridView is with the following information:
TreeView must be like below:
OBS.: I created a TreeView manually to try to explain how I want it to be.
I tried to do like this:
public void CarregaTreeView() {
string pai = "";
string filho = "";
string noPrincipal = "";
Dictionary<string, List<string>> dict = new Dictionary<string, List<string>>();
noPrincipal = dgv.Rows[0].Cells["COD_PAI"].Value.ToString();
foreach (DataGridViewRow row in dgv.Rows) {
pai = (string)row.Cells[0].Value;
filho = (string)row.Cells[3].Value;
if (dict.ContainsKey(pai)) {
dict[pai].Add(filho);
}
else {
dict.Add(pai, new List<string>());
dict[pai].Add(filho);
}
}
//adicionar nĂ³ principal
TreeNode objTopNode = new TreeNode(noPrincipal + " - DESCRICAO - [QTDE]");
tv.Nodes.Add(objTopNode);
objTopNode.Tag = noPrincipal;
MontaTreeView(dict, objTopNode);
}
private void MontaTreeView(Dictionary<string, List<string>> dict, TreeNode objparentNode) {
foreach (var kvp in dict) {
objcurrentNode = new TreeNode(kvp.Key + " - DESCRICAO - [QTDE]");
objparentNode.Nodes.Add(objcurrentNode);
objcurrentNode.Tag = kvp.Key;
objcurrentNode.Expand();
if (kvp.Key.Contains("T")) {
Dictionary<string, List<string>> dict1 = new Dictionary<string, List<string>>();
dict1.Add(kvp.Key, new List<string>());
dict1[kvp.Key].Add(dict[kvp.Key][0]);
MontaTreeView(dict1, objcurrentNode);
}
}
}
Basically, you need to iterate over your grid view. For each row, find its parent node in the tree, then add the row to the node children.
TreeNode findParent(string txt, TreeNode parent = null)
{
if (parent == null)
parent = treeView1.Nodes[0];
if (parent.Text == txt) return parent;
foreach (TreeNode node in parent.Children)
{
var res = findParent(txt, node); //recursion
if (res != null) return res;
}
return null;
}
foreach (DataGridViewRow row in dataGrid.Rows)
{
TreeNode parent = findParent(row.Cells[2].Value as string);
var newNode = new TreeNode() { Text = row.Cells[0].Value as Text };
if (parent != null)
parent.Children.Add(newNode);
else
treeView1.Nodes.Add(newNode);
}

Recursive tree search return wrong results

I have this implementation of a tree recursive function. It gets all possible paths from A to D.
The recursive function is:
private static List<Path> GetPath(int depth, Path path)
{
if (depth == nodes.Length)
{
return new List<Path> { path };
}
else
{
var result = new List<Path>();
foreach(var link in nodes[depth].Links)
{
Node node = new Node { Name = nodes[depth].Name, Links = new[] { link } };
path.Add(node);
result.AddRange(
GetPath(
depth+1, path));
}
return result;
}
}
The expected results should be:
A1-B2->C3->D4
A1-B5->C3->D4
However, the paths returned are the same and they include all possible nodes twice.
What's wrong with the function?
foreach(var link in nodes[depth].Links)
{
Node node = new Node { Name = nodes[depth].Name, Links = new[] { link } };
path.Add(node);
You probably intend to make a new path (which is a copy of path) for each node that you find here, before appending the next node.
As #moreON's suggest, I add clone function into class Path, and modify the loop, in loop i copy to new instance of path:
public class Path : List<Node>
{
public override string ToString()
{
String s = "";
foreach (var node in this)
{
s += node.Name + node.Links[0] + "->";
}
return s;
}
public Path Clone()
{
var newPath = new Path();
ForEach(x => newPath.Add(new Node {Name = x.Name, Links = new int[] {x.Links[0]}}));
return newPath;
}
}
private static List<Path> GetPath(int depth, Path path)
{
if (depth == nodes.Length)
{
return new List<Path> { path };
}
else
{
var result = new List<Path>();
foreach (var link in nodes[depth].Links)
{
Node node = new Node { Name = nodes[depth].Name, Links = new[] { link } };
var currentPath = path.Clone();
currentPath.Add(node);
result.AddRange(GetPath(depth + 1, currentPath));
}
return result;
}
}
Hope this help.

How add TreeNode to TreeNodeCollection with more than name and text in C#

I want to add to my treeview some nodes with childs, but have a problem how to add nodes with for example ToolTipText. I want do it with TreeNodeCollection.
It is possible or how could I change my code?
Here is my code where all nodes are root nodes.
protected void CreateTreeView(TreeNodeCollection parentNode, int parentID, DataTable mytab)
{
foreach (DataRow dta in mytab.Rows)
{
if (Convert.ToInt32(dta["parent_id"]) == parentID)
{
String key = dta["id"].ToString();
String text = dta["host_ip"].ToString();
TreeNode tn = new TreeNode();
tn.Name = dta["id"].ToString();
tn.Text = dta["host_ip"].ToString();
tn.ToolTipText = dta["description"].ToString();
parentNode.Add(tn);
TreeNodeCollection newParentNode = parentNode;
CreateTreeView(newParentNode, Convert.ToInt32(dta["id"]), mytab);
}
}
}
Calling code:
CreateTreeView(treeView1.Nodes, 0, dt);
If someone had with this problem here is an example:
void add_tooltiptext(DataTable mytab)
{
try
{
foreach (DataRow nodes in mytab.Rows)
{
TreeNode[] found = treeView1.Nodes.Find(nodes["id"].ToString(), true);
for (int i = 0; i < found.Length; i++)
{
treeView1.SelectedNode = found[i];
treeView1.SelectedNode.ToolTipText = nodes["description"].ToString();
}
}
}
catch
{ }
}

File System TreeView

Im working with file systems and I have a List<> of file objects that have the file path as a property. Basically I need to create a treeview in .NET but im struggling to think of the best way to go about doing this as I need to create a tree structure from a list like:
C:/WINDOWS/Temp/ErrorLog.txt
C:/Program Files/FileZilla/GPL.html
C:/Documents and Settings/Administrator/ntuser.dat.LOG
etc....
The list is not structured at all and I cant make any changes to the current object structure.
I'm working in C#.
Many thanks for all who contribute
If you wanted to stick with the strings something like this would work...
TreeNode root = new TreeNode();
TreeNode node = root;
treeView1.Nodes.Add(root);
foreach (string filePath in myList) // myList is your list of paths
{
node = root;
foreach (string pathBits in filePath.Split('/'))
{
node = AddNode(node, pathBits);
}
}
private TreeNode AddNode(TreeNode node, string key)
{
if (node.Nodes.ContainsKey(key))
{
return node.Nodes[key];
}
else
{
return node.Nodes.Add(key, key);
}
}
I would turn the string into a FileInfo.
Once you have the FileInfo object, you can use the Directory property to retrieve the DirectoryInfo for each path.
Once you have the DirectoryInfo for the path, it's easy to "walk up" the Parent reference in DirectoryInfo to turn each path into a list of directories + filename - ie:
{"C:","Windows","Temp","ErrorLog.txt"}
This should be fairly straightforward to insert into your treeview. Just look for each section of the path in turn, and if it doesn't exist, add it....
give recursion a try.
private void AddFiles()
{
// Iterate your list with FileInfos here
foreach( var fileInfo in new Collection<FileInfo>() )
{
GetOrCreateTreeNode( fileInfo.Directory ).Nodes.Add( new TreeNode( fileInfo.Name ) );
}
}
private TreeNode GetOrCreateTreeNode( DirectoryInfo directory )
{
if( directory.Parent == null )
{
// Access your TreeView control here:
var rootNode = <TreeView>.Nodes[directory.Name];
if( rootNode == null )
{
rootNode = new TreeNode(directory.Name);
// Access your TreeView control here:
<TreeView>.Nodes.Add( rootNode );
}
return rootNode;
}
var parent = GetOrCreateTreeNode( directory.Parent );
var node = parent.Nodes[directory.Name];
if( node == null )
{
node = new DirectoryNode( directory );
parent.Nodes.Add( node );
}
return node;
}
This code should give you only an idea - I have to admit that I did not test it before posting here.
private void Form1_Load(object sender, EventArgs e)
{
var paths = new List<string>
{
#"C:\WINDOWS\AppPatch\MUI\040C",
#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727",
#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI",
#"C:\WINDOWS\addins",
#"C:\WINDOWS\AppPatch",
#"C:\WINDOWS\AppPatch\MUI",
#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MUI\0409"
};
treeView1.PathSeparator = #"\";
PopulateTreeView(treeView1, paths, '\\');
}
private static void PopulateTreeView(TreeView treeView, IEnumerable<string> paths, char pathSeparator)
{
TreeNode lastNode = null;
string subPathAgg;
foreach (string path in paths)
{
subPathAgg = string.Empty;
foreach (string subPath in path.Split(pathSeparator))
{
subPathAgg += subPath + pathSeparator;
TreeNode[] nodes = treeView.Nodes.Find(subPathAgg, true);
if (nodes.Length == 0)
if (lastNode == null)
lastNode = treeView.Nodes.Add(subPathAgg, subPath);
else
lastNode = lastNode.Nodes.Add(subPathAgg, subPath);
else
lastNode = nodes[0];
}
}
}
EHosca's piece worked for me perfectly, with one change - I had to set lastnode to nothing after the foreach path in paths area.
This is eHosca's code above, ported to VB.
Private Sub PopulateTreeView(tv As TreeView, paths As List(Of String), pathSeparator As Char)
Dim lastnode As TreeNode = Nothing
Dim subPathAgg As String
For Each path In paths
subPathAgg = String.Empty
lastnode = Nothing
For Each subPath In path.Split(pathSeparator)
subPathAgg += subPath + pathSeparator
Dim nodes() As TreeNode = tv.Nodes.Find(subPathAgg, True)
If nodes.Length = 0 Then
If IsNothing(lastnode) Then
lastnode = tv.Nodes.Add(subPathAgg, subPath)
Else
lastnode = lastnode.Nodes.Add(subPathAgg, subPath)
End If
Else
lastnode = nodes(0)
End If
Next
Next
End Sub

Categories

Resources