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?
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!