Как рекурсивно заполнить TreeView данными JSON

У меня есть древовидное представление winforms, я могу читать данные автоматически (узел, равный ключу, и узел внутри, равный значению), но при чтении типа объекта значения внутри него не будут дочерними по отношению к объекту узел (ключ объекта), (возможно, я не смог объяснить, вот скриншот и мои методы.)

layer0 должен быть внутри текстур, а масштаб должен быть внутри дисплея

layer0 должен быть внутри текстур, а масштаб должен быть внутри дисплея

Мой Джсон:

{
"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);
            }
        }

    }

Я пытался получить родителя, но у него не было свойств name и value:S. Любая помощь? (Извините за языковые ошибки)

2 ответа

Решение

Проблема в том, что при рекурсивном JToken иерархии, вы также должны рекурсивно опускать TreeNode Иерархия, которую вы создаете, добавление дочерних узлов к только что созданному родительскому узлу, а не корневому узлу, по линиям Рекурсии, синтаксический анализ файла XML с атрибутами в виде дерева 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
        }
    }

Вы получите следующую древовидную структуру:

Вот моя трещина в этом. Выходные данные идентичны плагину JSTool для Notepad++: TreeView показывает JSON

Код структурирован как расширение 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());
Другие вопросы по тегам