在前文《C#使用XML和Treeview结合实现复杂数据采集功能》中,使用Treeview展示了XML的数据,问题是如果在Treeview上进行了操作,怎样同步更改XML数据的内容呢?
这个问题看似简单,实现起来有一点小麻烦。
要实现的操作功能:
⑴如果点击了Radio,即单选图标,需要在XML文档中找到该节点,将同级的所有节点的选择属性清空,然后将该节点的选择属性置为“true”。
⑵如果点击了Checkbox,即多选图标,需要在XML文档中找到该节点,然后将该节点的选择属性置为“true”。
⑶如果点击了textbook,即文本输入图标,需要在XML文档中找到该节点,然后改写该节点的value属性值。
⑷点击标签,只进行图标替换动作,不更改XML内容。
⑸只要点击Radio、Checkbox、textbook,都需要进行自动计算。自动计算规则:没有计算公式属性,那么父节点等于子节点的value之和,如果有计算公式,需要根据计算公式进行结果获取。
这里记录解决⑴、⑵、⑶的代码实现。
在treeView1_MouseDown(object sender, MouseEventArgs e)事件中的具体实现代码:
//在XML内容中进行操作,找到该子项目并修改子项目的属性值,就是修改XML文档的内容
//找到该节点
TreeNode SelectedNode =treeView1.GetNodeAt(e.X, e.Y);
//得到全路径名
string StrCurrentPath= SelectedNode.FullPath;
//找第一个"\"
int FirstIndex = StrCurrentPath.IndexOf("\\");
//找最后一个"\"
int LastIndex =StrCurrentPath.LastIndexOf("\\");
//得到在XML文档中父节点的全路径名称
string StrParentPath= StrCurrentPath.Substring(FirstIndex+1,LastIndex - FirstIndex -1);
//得到当前节点名称
string StrCurrentNodeName= StrCurrentPath.Substring(LastIndex+1);
//找到节点
XmlNode TargetNode = FindNodeAtXmlContent(XmlDoc.DocumentElement, StrParentPath);
//处理节点信息
HandleNodeInfoAtXmlContent(TargetNode, StrCurrentNodeName);
//保存处理后的XML文档内容
StrXmlContent = XmlDoc.OuterXml;
查找函数,根据被查找的节点和路径找到该节点。
一般情况下使用递归来进行查找,这里使用的循环:
将路径进行拆解到一个字符串数组中,比如“\节点1\节点2\节点3\节点4”,拆解成"节点1"、"节点2"、“节点3”、“节点4”,先找“节点1”,然后依次找后面的,这样快。
实现的代码:
private XmlNode FindNodeAtXmlContent(XmlNode BeSearchedNode,string StrFullPath)
{
XmlNode CurrentNode=BeSearchedNode;
string[] StrPathAll= StrFullPath.Split('\\');
foreach(string StrPath in StrPathAll)
{
bool Finded= false;
foreach(XmlNode xmlNode in CurrentNode.ChildNodes)
{
if (xmlNode.Name.Trim()==StrPath.Trim())
{
Finded = true;
CurrentNode= xmlNode;//找到对应的节点
break;
}
}
if(!Finded)
{
return null;//没有找到对应的节点
}
}
return CurrentNode;
}
处理函数,如果找到了父节点,就更改相关信息:
private void HandleNodeInfoAtXmlContent(XmlNode ParentNode,string StrChildNodeName)
{
XmlNode BeSelectChildNode =null;
//根据父节点和子节点的名称(caption属性)处理XML文档
if (ParentNode.Attributes["type"] != null)
{
string StrNodeType = ParentNode.Attributes["type"].Value;
if (StrNodeType=="Radio")
{
foreach(XmlNode ChildNode in ParentNode.ChildNodes)
{
textBox2.Text += "节点caption:" + ChildNode.Attributes["caption"].Value+Environment.NewLine;
//单选,先将父节点下的子节点的select属性全部删除
if (ChildNode.Attributes["select"] != null)
{
ChildNode.Attributes.Remove(ChildNode.Attributes["select"]);
}
//找到子节点
if (ChildNode.Attributes["caption"].Value ==StrChildNodeName.Trim())
{
BeSelectChildNode = ChildNode;
}
}
//添加select属性
XmlAttribute SelectedAttr = XmlDoc.CreateAttribute("select");
SelectedAttr.Value= "true";
BeSelectChildNode.Attributes.Append(SelectedAttr);
}
if (StrNodeType == "Checkbox")
{
foreach (XmlNode ChildNode in ParentNode.ChildNodes)
{
//多选,找到并添加select属性
//找到子节点
if (ChildNode.Attributes["caption"].Value == StrChildNodeName.Trim())
{
BeSelectChildNode = ChildNode;
}
}
//添加select属性
XmlAttribute SelectedAttr = XmlDoc.CreateAttribute("select");
SelectedAttr.Value = "true";
BeSelectChildNode.Attributes.Append(SelectedAttr);
}
if (StrNodeType == "Textbox")
{
foreach (XmlNode ChildNode in ParentNode.ChildNodes)
{
//文本输入框,找到并更改value属性
//找到子节点
if (ChildNode.Attributes["caption"].Value == StrChildNodeName.Trim())
{
BeSelectChildNode = ChildNode;
}
}
//更改value属性属性
XmlAttribute SelectedAttr = XmlDoc.CreateAttribute("value");
SelectedAttr.Value = StrCurrentTextboxValue;
BeSelectChildNode.Attributes.Append(SelectedAttr);
}
}
}
通过上面的代码,就可以做到Treeview的操作与实际XML文档内容的同步更新和一致。