如何使用 JSON 数据递归填充 TreeView
Posted
技术标签:
【中文标题】如何使用 JSON 数据递归填充 TreeView【英文标题】:How to recursively populate a TreeView with JSON data 【发布时间】:2017-02-02 02:01:04 【问题描述】:我有一个winforms treeview,我可以自动读取数据,(一个节点等于key,一个节点里面等于value),但是读取对象类型时,里面的值不会是对象节点的子节点(对象的键),(可能我解释不好,这里是截图和我的方法。)
layer0 需要在纹理内部,比例需要在显示内部
我的 Json:
"parent": "builtin/generated",
"textures":
"layer0": "mm:items/iron_dust"
,
"display":
"scale": [ 1.7, 1.7, 1.7 ]
我的自动检测方法(实际上并非都是我的)
private void Form1_Load(object sender, EventArgs e)
StreamReader reader = new StreamReader(path);
string json = reader.ReadToEnd();
reader.Close();
JObject obj = JObject.Parse(json);
getAllProperties(obj);
void getAllProperties(JToken children)
TreeNode mainNode = treeView1.Nodes[0];
mainNode.Text = Path.GetFileNameWithoutExtension(path);
foreach (JToken child in children.Children())
var property = child as JProperty;
if (property != null)
if (property.Value.Type == JTokenType.String)
TreeNode keyNode = mainNode.Nodes.Add(property.Name);
keyNode.Nodes.Add(property.Value.ToString());
if (property.Value.Type == JTokenType.Array)
JArray array = (JArray)property.Value;
TreeNode node = mainNode.Nodes.Add(property.Name);
for (int i = 0; i < array.Count; i++)
node.Nodes.Add(array[i].ToString());
if (property.Value.Type == JTokenType.Object)
TreeNode topNode = mainNode.Nodes.Add(property.Name.ToString());
foreach (var item in property)
if (item.Type == JTokenType.String)
if (property.Value.Type == JTokenType.String)
TreeNode keyNode = topNode.Nodes.Add(property.Name);
keyNode.Nodes.Add(property.Value.ToString());
if (property.Value.Type == JTokenType.Array)
JArray array = (JArray)property.Value;
TreeNode node = topNode.Nodes.Add(property.Name);
for (int i = 0; i < array.Count; i++)
node.Nodes.Add(array[i].ToString());
// Console.WriteLine(property.Name + ":" + property.Value);//print all of the values
getAllProperties(child);
我尝试获取父级,但它没有名称和值属性:S。 有什么帮助吗? (语言错误见谅)
【问题讨论】:
也许this thread 能帮上忙? 我会尽可能尝试:)(我现在不能尝试)但是..我不明白 walknode 在这里做什么。你能解释一下吗?WalkNode
的工作方式如下:从参数中获取节点,然后遍历节点的每个子节点。它应用 Action
函数(在您的情况下可以添加到 MainNode 中),然后更深入 - 在子节点上调用 WalkNode
。基本上,它递归遍历 JSON 中的所有节点。
你可以复制你在foreach
循环中的逻辑(你在这里访问你的TreeNode的mainNode,对吧?)并将它插入Action
函数中,在WalkNode
中引用
可能是的,但我不能确定,因为我没有尝试使用你的代码,也没有自己用这种方式解析 JSON。
【参考方案1】:
问题是,当您递归下降JToken
层次结构时,您还需要递归下降您正在创建的TreeNode
层次结构,将子节点添加到刚刚创建的父节点,而不是根节点,沿Recursion, parsing xml file with attributes into treeview c# 的行。
如果你这样做:
private void Form1_Load(object sender, EventArgs e)
using (var reader = new StreamReader(path))
using (var jsonReader = new JsonTextReader(reader))
var root = JToken.Load(jsonReader);
DisplayTreeView(root, Path.GetFileNameWithoutExtension(path));
private void DisplayTreeView(JToken root, string rootName)
treeView1.BeginUpdate();
try
treeView1.Nodes.Clear();
var tNode = treeView1.Nodes[treeView1.Nodes.Add(new TreeNode(rootName))];
tNode.Tag = root;
AddNode(root, tNode);
treeView1.ExpandAll();
finally
treeView1.EndUpdate();
private void AddNode(JToken token, TreeNode inTreeNode)
if (token == null)
return;
if (token is JValue)
var childNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(token.ToString()))];
childNode.Tag = token;
else if (token is JObject)
var obj = (JObject)token;
foreach (var property in obj.Properties())
var childNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(property.Name))];
childNode.Tag = property;
AddNode(property.Value, childNode);
else if (token is JArray)
var array = (JArray)token;
for (int i = 0; i < array.Count; i++)
var childNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(i.ToString()))];
childNode.Tag = array[i];
AddNode(array[i], childNode);
else
Debug.WriteLine(string.Format("0 not implemented", token.Type)); // JConstructor, JRaw
您将获得以下树状视图结构:
【讨论】:
哇!这就是我所需要的。但我想知道一些事情。这是否适用于布尔值: if (token is JBoolean) var childNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(token.ToString()))]; childNode.Tag = 令牌; 没有JBoolean
这样的东西。布尔值存储在JValue
。所有具体的 linq-to-JSON 类型的集合显示在 this answer 中。【参考方案2】:
这是我的破解之道。输出与 Notepad++ 的 JSTool 插件相同:
代码结构为 TreeView 扩展:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Windows.Forms;
namespace TestDLApp.Utilities.Extensions
public static class ObjectToTreeView
private sealed class IndexContainer
private int _n;
public int Inc() => _n++;
private static void FillTreeView(TreeNode node, JToken tok, Stack<IndexContainer> s)
if (tok.Type == JTokenType.Object)
TreeNode n = node;
if(tok.Parent != null)
if(tok.Parent.Type == JTokenType.Property)
n = node.Nodes.Add($"((JProperty)tok.Parent).Name <tok.Type.ToString()>");
else
n = node.Nodes.Add($"[s.Peek().Inc()] <tok.Type.ToString()>");
s.Push(new IndexContainer());
foreach (var p in tok.Children<JProperty>())
FillTreeView(n, p.Value, s);
s.Pop();
else if (tok.Type == JTokenType.Array)
TreeNode n = node;
if(tok.Parent != null)
if (tok.Parent.Type == JTokenType.Property)
n = node.Nodes.Add($"((JProperty)tok.Parent).Name <tok.Type.ToString()>");
else
n = node.Nodes.Add($"[s.Peek().Inc()] <tok.Type.ToString()>");
s.Push(new IndexContainer());
foreach (var p in tok)
FillTreeView(n, p, s);
s.Pop();
else
var name = string.Empty;
var value = JsonConvert.SerializeObject(((JValue)tok).Value);
if (tok.Parent.Type == JTokenType.Property)
name = $"((JProperty)tok.Parent).Name : value";
else
name = $"[s.Peek().Inc()] : value";
node.Nodes.Add(name);
public static void SetObjectAsJson<T>(this TreeView tv, T obj)
tv.BeginUpdate();
try
tv.Nodes.Clear();
var s = new Stack<IndexContainer>();
s.Push(new IndexContainer());
FillTreeView(tv.Nodes.Add("ROOT"), JsonConvert.DeserializeObject<JToken>(JsonConvert.SerializeObject(obj)), s);
s.Pop();
finally
tv.EndUpdate();
你可以这样称呼它:
treeView1.SetObjectAsJson(new MyNeatObject());
【讨论】:
以上是关于如何使用 JSON 数据递归填充 TreeView的主要内容,如果未能解决你的问题,请参考以下文章