Search code examples
c#serializationtreeviewdeserialization

Converting tree view to byte[], then back again


I'm trying to convert a treeview to a byte array and then back again. So far when the form loads, it will load the structure of my documents. Then as far as I know, it will convert it to a byte array and back but I'm not sure how to convert the byte array back to the tree view.

Here is my code:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        string filepath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        ListDirectory(treeView1, filepath);
    }

    private static void ListDirectory(TreeView treeView, string path)
    {
        treeView.Nodes.Clear();

        var stack = new Stack<TreeNode>();
        var rootDirectory = new DirectoryInfo(path);
        var node = new TreeNode(rootDirectory.Name) { Tag = rootDirectory };
        stack.Push(node);

        while (stack.Count > 0)
        {
            var currentNode = stack.Pop();
            var directoryInfo = (DirectoryInfo)currentNode.Tag;

            foreach (var directory in directoryInfo.GetDirectories())
            {
                var childDirectoryNode = new TreeNode(directory.Name) { Tag = directory };
                currentNode.Nodes.Add(childDirectoryNode);
                stack.Push(childDirectoryNode);
            }

            foreach (var file in directoryInfo.GetFiles())
                currentNode.Nodes.Add(new TreeNode(file.Name));
        }

        treeView.Nodes.Add(node);
    }

    private Byte[] SerilizeQueryFilters()
    {
        BinaryFormatter bf = new BinaryFormatter();

        List<TreeNode> list = new List<TreeNode>();

        foreach(TreeNode node in treeView1.Nodes)
        {
            list.Add(node);
        }

        using (MemoryStream ms = new MemoryStream())
        {
            bf.Serialize(ms, list);
            return ms.GetBuffer();
        }
    }

    private void DeSerilizeQueryFilters(byte[] items)
    {
        BinaryFormatter bf = new BinaryFormatter();

        try
        {
            using (MemoryStream ms = new MemoryStream())
            {
                ms.Write(items, 0, items.Length);
                ms.Position = 0;
                _list = bf.Deserialize(ms) as List<TreeNode>;
                treeView2.Nodes.AddRange(_list.ToArray());
            }
        }
        catch(Exception e)
        { 
            Console.WriteLine(e.StackTrace);
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        byte[] data = SerilizeQueryFilters();
        DeSerilizeQueryFilters(data);
    }
}

So the bit that's throwing an error at the moment is

_list = bf.Deserialize(ms) as List<TreeNode>;

and I get this error:

System.Runtime.Serialization.SerializationException

Does anyone have any ideas?


Solution

  • The solution was easy using the recommendation of @Fildor I stop using BinaryFormatter and now I use JSON and using the recommendation of @madreflection I create a custom class to save the data of the TreeNode.

    Custom TreeNode Class

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TreeViewStuff
    {
        public class Node
        {
            public int id;
            public string text = "";
            public int parentId = 0;
            public bool cheked = false;
        }
    }
    

    Deserialize/Serialize TreeView Class

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace TreeViewStuff
    {
        public class TreeviewPersist
        {
    
            public static string strJson;
            private static TreeView treeView_;
    
            static public string ToJson(TreeView treeView)
            {
                List<Node> nodes = new List<Node>();
    
                foreach(TreeNode node in treeView.Nodes) 
                {
                    SerializeTree(nodes, node);
                }
    
                nodes.RemoveAt(0);
    
                return JsonConvert.SerializeObject(nodes);
            }
    
            public delegate void FunctionDelegate();
    
            public static void FromJson(string strJson_, TreeView treeView)
            {
                strJson = strJson_;
                treeView_ = treeView;
    
                treeView.BeginInvoke(new FunctionDelegate(FromJson));
            }
    
            private static void FromJson()
            {
                treeView_.Nodes.Clear();
    
                List<Node> nodes = JsonConvert.DeserializeObject<List<Node>>(strJson);
    
                foreach(Node node in nodes)
                {
                    if (node.parentId == 0)
                    {
                        TreeNode treeNode = treeView_.Nodes.Add(node.text);
                        treeNode.Name = $"{node.id}";
                        treeNode.Checked = node.cheked;
                    }
                    else
                    {
                        TreeNode[] foundNodes = treeView_.Nodes.Find($"{node.parentId}", true);
                        if (foundNodes.Length > 0)
                        {
                            TreeNode treeNode = foundNodes[0].Nodes.Add(node.text);
                            treeNode.Checked = node.cheked;
                            treeNode.Name = $"{node.id}";
                        }
                    }
                }
            }
    
            static private void SerializeTree(List<Node> nodes, TreeNode treeNode)
            {
                Node node = new Node();
    
                bool suces = Int32.TryParse(treeNode.Name, out node.id);
    
                TreeNode parent = treeNode.Parent;
                if (parent != null)
                {
                    suces = Int32.TryParse(parent.Name, out node.parentId);
                }
                else
                {
                    node.parentId = 0;
                }
    
                node.text = treeNode.Text;
                node.cheked = treeNode.Checked;
    
                nodes.Add(node);
    
                foreach (TreeNode tn in treeNode.Nodes)
                {
                    SerializeTree(nodes, tn);
                }
            }
        }
    }
    

    Directories/Files to TreeView Method

    private static void ListDirectory(TreeView treeView, string path)
    {
        treeView.Nodes.Clear();
    
        int id = 1;
    
        var stack = new Stack<TreeNode>();
        var rootDirectory = new DirectoryInfo(path);
        var node = new TreeNode(rootDirectory.Name) { Tag = rootDirectory };
        stack.Push(node);
    
        while (stack.Count > 0)
        {
            var currentNode = stack.Pop();
            var directoryInfo = (DirectoryInfo)currentNode.Tag;
            foreach (var directory in directoryInfo.GetDirectories())
            {
                var childDirectoryNode = new TreeNode(directory.Name) { Tag = directory };
                childDirectoryNode.Name = $"{id++}";
                currentNode.Nodes.Add(childDirectoryNode);
                stack.Push(childDirectoryNode);
            }
            foreach (var file in directoryInfo.GetFiles())
            {
                TreeNode treeNode = new TreeNode(file.Name);
                treeNode.Name = $"{id++}";
                currentNode.Nodes.Add(new TreeNode(file.Name));
            }
    
        }
    
        treeView.Nodes.Add(node);
    }
    

    To make this work each TreeNode needs to have a Unique Id that is going to be saved in the name of the TreeNode as I do in the Directories/Files to TreeView Method. Thanks @Fildor and @madreflection for your help!