如何持久化附带Machine对象的TreeView节点Tag属性?
解决方案:序列化Machine类以保留TreeView节点Tag的实际数据
是的,你必须对Machine类进行序列化处理,才能在XML持久化时保存它的IP、FQDN和友好名称等实际数据,之后程序启动反序列化TreeView时,再将重建的Machine对象绑定到对应节点的Tag属性上。以下是具体实现步骤:
1. 让Machine类支持序列化
给Machine类添加[Serializable]特性,并确保有无参构造函数(反序列化必须依赖无参构造函数重建对象):
[Serializable] public class Machine { public string MachineFQDN { get; set; } public string MachineName { get; set; } public string MachineIP { get; set; } // 反序列化必须的无参构造函数 public Machine() { } public Machine(string fqdn, string name, string ip) { MachineFQDN = fqdn; MachineName = name; MachineIP = ip; } }
2. 修改TreeViewSerializer的序列化逻辑
原来的代码直接调用node.Tag.ToString()只会保存类名,现在要判断Tag是否为Machine类型,将其属性序列化为XML子元素:
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) { if (node.Tag is Machine machine) { // 将Machine的属性写入XML子节点 textWriter.WriteStartElement("Machine"); textWriter.WriteElementString("FQDN", machine.MachineFQDN); textWriter.WriteElementString("Name", machine.MachineName); textWriter.WriteElementString("IP", machine.MachineIP); textWriter.WriteEndElement(); } else { // 兼容其他类型的Tag,保留原逻辑 textWriter.WriteAttributeString(XmlNodeTagAtt, node.Tag.ToString()); } } if (node.Nodes.Count > 0) { SaveNodes(node.Nodes, textWriter); } textWriter.WriteEndElement(); } }
3. 修改TreeViewSerializer的反序列化逻辑
读取XML时识别Machine子元素,重建Machine对象并赋值给节点的Tag:
public void DeserializeTreeView(TreeView tv, string filename) { XmlTextReader reader = null; try { tv.BeginUpdate(); reader = new XmlTextReader(filename); TreeNode parentNode = null; TreeNode currentNode = null; while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { if (reader.Name == XmlNodeTag) { TreeNode newNode = new TreeNode(); bool isEmptyElement = reader.IsEmptyElement; // 加载节点基础属性 int attributeCount = reader.AttributeCount; if (attributeCount > 0) { for (int i = 0; i < attributeCount; i++) { reader.MoveToAttribute(i); SetAttributeValue(newNode, reader.Name, reader.Value); } } // 添加节点到TreeView或父节点 if (parentNode != null) parentNode.Nodes.Add(newNode); else tv.Nodes.Add(newNode); currentNode = newNode; if (!isEmptyElement) { parentNode = newNode; } } else if (reader.Name == "Machine" && currentNode != null) { // 读取Machine数据并创建对象 Machine machine = new Machine(); while (reader.Read() && reader.NodeType != XmlNodeType.EndElement) { if (reader.NodeType == XmlNodeType.Element) { switch (reader.Name) { case "FQDN": machine.MachineFQDN = reader.ReadElementContentAsString(); break; case "Name": machine.MachineName = reader.ReadElementContentAsString(); break; case "IP": machine.MachineIP = reader.ReadElementContentAsString(); break; } } } currentNode.Tag = machine; } } else if (reader.NodeType == XmlNodeType.EndElement) { if (reader.Name == XmlNodeTag) { parentNode = parentNode?.Parent; currentNode = parentNode; } } // 保留原有其他节点类型的处理逻辑 else if (reader.NodeType == XmlNodeType.XmlDeclaration) { // 忽略XML声明 } else if (reader.NodeType == XmlNodeType.None) { return; } else if (reader.NodeType == XmlNodeType.Text) { if (parentNode != null) parentNode.Nodes.Add(reader.Value); } } } finally { tv.EndUpdate(); reader?.Close(); } }
为什么原来的代码无法保存实际数据?
你之前的代码调用node.Tag.ToString()时,默认返回的是Machine类的完全限定名(比如PRTG_Ripoff.Machine),并没有序列化对象的属性值。只有将对象的具体数据转换成XML可存储的结构,反序列化时才能重建完整的Machine对象并绑定到节点的Tag上。
内容的提问来源于stack exchange,提问作者Thomton
相关产品推荐
相关产品推荐

