I've created a TreeView, in which some of the nodes have the Tag property set as an object Machine
which contains an IP address, FQDN and a friendly name as strings
I can persist the TreeView, keeping the structure of the tree when reloading the program using XML. However, the Tag value is just Project.Machine
and obviously doesn't contain the data.
The program works by asking the user to input the data into textboxes, which are then created into the machine object, and then tied to the selected nodes Tag property.
Should I serealize the class and then add the Tag property to the node when the program initiates?
Here's the class to persist the TreeView
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace PRTG_Ripoff
{
internal class TreeViewSerializer
{
// Constants
// Xml tag for node
private const string XmlNodeTag = "node";
// Xml attributes for node
private const string XmlNodeTextAtt = "text";
private const string XmlNodeTagAtt = "tag";
private const string XmlNodeImageIndexAtt = "imageindex";
public void DeserializeTreeView(TreeView tv, string filename)
{
XmlTextReader reader = null;
try
{
// disable re-drawing of tree view till nodes are added
tv.BeginUpdate();
reader = new XmlTextReader(filename);
TreeNode parentNode = null;
while(reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name == XmlNodeTag)
{
TreeNode newNode = new TreeNode();
bool isEmptyElement = reader.IsEmptyElement;
// loading node attributes
int attributeCount = reader.AttributeCount;
if (attributeCount > 0)
{
for (int i = 0; i < attributeCount; i )
{
reader.MoveToAttribute(i);
SetAttributeValue(newNode,
reader.Name, reader.Value);
}
}
// add new node to Parent Node or TreeView
if (parentNode != null)
parentNode.Nodes.Add(newNode);
else
tv.Nodes.Add(newNode);
// making current node 'ParentNode' if its not empty
if (!isEmptyElement)
{
parentNode = newNode;
}
}
}
// moving up to in TreeView if end tag is encountered
else if (reader.NodeType == XmlNodeType.EndElement)
{
if (reader.Name == XmlNodeTag)
{
parentNode = parentNode.Parent;
}
}
else if (reader.NodeType == XmlNodeType.XmlDeclaration)
{
//Ignore Xml Declaration
}
else if (reader.NodeType == XmlNodeType.None)
{
return;
}
else if (reader.NodeType == XmlNodeType.Text)
{
parentNode.Nodes.Add(reader.Value);
}
}
}
finally
{
// enabling redrwaing of treeview
tv.EndUpdate();
reader.Close();
}
}
/// Used by Deserialize method for setting properties of
/// TreeNode from xml node attributes
private void SetAttributeValue(TreeNode node,
string propertyName, string value)
{
if (propertyName == XmlNodeTextAtt)
{
node.Text = value;
}
else if (propertyName == XmlNodeImageIndexAtt)
{
node.ImageIndex = int.Parse(value);
}
else if (propertyName == XmlNodeTagAtt)
{
node.Tag = value;
}
}
public void SerializeTreeView(TreeView treeView, string fileName)
{
XmlTextWriter textWriter = new XmlTextWriter(fileName,
System.Text.Encoding.ASCII);
// writing the xml declaration tag
textWriter.WriteStartDocument();
//textWriter.WriteRaw("\r\n");
// writing the main tag that encloses all node tags
textWriter.WriteStartElement("TreeView");
// save the nodes, recursive method
SaveNodes(treeView.Nodes, textWriter);
textWriter.WriteEndElement();
textWriter.Close();
}
private void SaveNodes(TreeNodeCollection nodesCollection, XmlTextWriter textWriter)
{
for (int i = 0; i < nodesCollection.Count; i )
{
TreeNode node = nodesCollection[i];
textWriter.WriteStartElement(XmlNodeTag);
textWriter.WriteAttributeString(XmlNodeTextAtt,
node.Text);
textWriter.WriteAttributeString(
XmlNodeImageIndexAtt, node.ImageIndex.ToString());
if (node.Tag != null)
textWriter.WriteAttributeString(XmlNodeTagAtt,
node.Tag.ToString());
// add other node properties to serialize here
if (node.Nodes.Count > 0)
{
SaveNodes(node.Nodes, textWriter);
}
textWriter.WriteEndElement();
}
}
}
}
And how I'm creating the object
private void Details_Btn_Click(object sender, EventArgs e)
{
// If the text boxes aren't empty
if (FQDN_Txt.Text != "" && IP_Txt.Text != "" && Name_Txt.Text != "")
{
if(mainTree.SelectedNode == null)
{
// If no node is selected
MessageBox.Show("Select a node!");
} else
{
// Create new machine object using data from the text boxes
Machine machine = new Machine(FQDN_Txt.Text, Name_Txt.Text, IP_Txt.Text);
// Set the tag as the machine object
mainTree.SelectedNode.Tag = machine;
}
} else
{
MessageBox.Show("these are empty mate");
}
}
And how I'm retrieving the data from the Tag
property
private void mainTree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
mainTree.SelectedNode = e.Node;
TreeNode tn = mainTree.SelectedNode;
infoPanel.Visible = true;
MachineName_lbl.Text = tn.Text;
if (mainTree.SelectedNode.Tag != null)
{
IP_Lbl.Text = ((Machine)mainTree.SelectedNode.Tag).MachineIP;
}
}
CodePudding user response:
As you don't currently use the Machine object instance anywhere else, then rather than create a complete instance and save it in Tag
you could instead just create either a Tuple
or KeyValuePair
and save that in the Tag
.
Then you can easily Serialise these values when you write your nodes in SaveNodes
. (and then read it again and create and add the Tuple
/ KeyValuePair
).
If you later need to use the Machine object, then you could just seralise the key and then do a look-up from your collection of Machine
. Either do this when you need it, or at the time you create your Treeview Nodes (and asign it to Tag).