How to recursively populate a TreeView with JSON data

人走茶凉 提交于 2019-11-27 16:06:58

The problem is that, as you recursively descend the JToken hierarchy, you also need to recursively descend the TreeNode hierarchy you are creating, adding child nodes to the parent node just created, rather than the root node, along the lines of Recursion, parsing xml file with attributes into treeview c#.

Thus if you do:

    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
        }
    }

You will get the following tree view structure:

Here is my crack at it. The output is identical to Notepad++'s JSTool plug-in:

The code is structured as a TreeView extension:

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();
            }
        }
    }
}

You can call it as so:

treeView1.SetObjectAsJson(new MyNeatObject());
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!