在winform中做了一个TreeView,节点数据存在XML文件里面,现在想用TreeNode节点属性Tag存储些数据,于是将Dictionary
这是从xml读出文件获取TreeView节点的代码
private void XmlNode2TreeNode(XmlNodeList xmlNode, TreeNodeCollection treeNode)
{
foreach (XmlNode xmlnode in xmlNode)
{
if (xmlnode.NodeType != XmlNodeType.Element) //忽略非Element类型的节点
{
continue;
}
TreeNode treenode = new TreeNode(); //新建一个TreeNode,并根据XML节点的Title属性设置文本
treenode.Text = xmlnode.Attributes["Title"].Value;
if (xmlnode.HasChildNodes) //如果XML节点有子节点,则递归调用XmlNode2TreeNode方法转换子节点
{
if (xmlnode.ChildNodes[0].NodeType == XmlNodeType.CDATA) //如果第一个子节点是CDATA,则将其内容作为TreeNode的Tag
{
dict["tag"] = xmlnode.ChildNodes[0].Value;
treenode.Tag = dict;
if (dict["tag"].Equals("root"))
{
treenode.ImageIndex = 0;
treenode.SelectedImageIndex = 0;
}
else if (dict["tag"].Equals("area"))
{
treenode.ImageIndex = 1;
treenode.SelectedImageIndex = 1;
}
else if (dict["tag"].Equals("user"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
else if (dict["tag"].Equals("lowest"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
}
//将新建的TreeNode添加到父TreeNode的Nodes 集合中
XmlNode2TreeNode(xmlnode.ChildNodes, treenode.Nodes);
}
//将新建的TreeNode添加到TreeView的节点集合中
treeNode.Add(treenode);
}
}
这是运行的样子
下面是鼠标事件的代码
private void treeView1_MouseUp(object sender, MouseEventArgs e)
{
try
{
Point mpt = new Point(e.X, e.Y);
TreeNode TreeClickNode = this.treeView1.GetNodeAt(mpt);
if (TreeClickNode != null)
{
dict = (Dictionary<string, string>)TreeClickNode.Tag;
CreatMenu(dict["tag"]); // dict["tag"]里面是node的级别(root,area,user,lowest)
//CreatMenu(TreeClickNode1.Tag.ToString());
if (e.Button == MouseButtons.Right)
{
this.contextMenuStrip.Show(this.treeView1, mpt); //在mpt位置实现treeview1的点击菜单栏
//this.treeView1.ContextMenu.Show(treeView1,mpt);
}
}
else
{
contextMenuStrip.Items.Clear();
}
}
catch
{
}
}
现在右键点击显示菜单的时候一般都只能得到级别都是user,右键点击菜单里面有添加最低一层节点,在添加最低一层节点后点击事件就只能获取到lowset这个级别了,应该是xml读取的地方出问题了但是又找不到是哪里。
如果不将Dictionary
private void XmlNode2TreeNode(XmlNodeList xmlNode, TreeNodeCollection treeNode)
{
foreach (XmlNode xmlnode in xmlNode)
{
if (xmlnode.NodeType != XmlNodeType.Element) //忽略非Element类型的节点
{
continue;
}
TreeNode treenode = new TreeNode(); //新建一个TreeNode,并根据XML节点的Title属性设置文本
treenode.Text = xmlnode.Attributes["Title"].Value;
if (xmlnode.HasChildNodes) //如果XML节点有子节点,则递归调用XmlNode2TreeNode方法转换子节点
{
if (xmlnode.ChildNodes[0].NodeType == XmlNodeType.CDATA) //如果第一个子节点是CDATA,则将其内容作为TreeNode的Tag
{
treenode.Tag = xmlnode.ChildNodes[0].Value;
if (treenode.Tag.ToString().Equals("root"))
{
treenode.ImageIndex = 0;
treenode.SelectedImageIndex = 0;
treenode.Expand();
}
else if (treenode.Tag.ToString().Equals("area"))
{
treenode.ImageIndex = 1;
treenode.SelectedImageIndex = 1;
}
else if (treenode.Tag.ToString().Equals("user"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
else
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
}
//将新建的TreeNode添加到父TreeNode的Nodes 集合中
XmlNode2TreeNode(xmlnode.ChildNodes, treenode.Nodes);
}
//将新建的TreeNode添加到TreeView的节点集合中
treeNode.Add(treenode);
}
}
基于Monster 组和GPT的调写:
修改后的代码如下:
private void XmlNode2TreeNode(XmlNodeList xmlNode, TreeNodeCollection treeNode)
{
foreach (XmlNode xmlnode in xmlNode)
{
if (xmlnode.NodeType != XmlNodeType.Element) //忽略非Element类型的节点
{
continue;
}
TreeNode treenode = new TreeNode(); //新建一个TreeNode,并根据XML节点的Title属性设置文本
treenode.Text = xmlnode.Attributes["Title"].Value;
if (xmlnode.HasChildNodes) //如果XML节点有子节点,则递归调用XmlNode2TreeNode方法转换子节点
{
if (xmlnode.ChildNodes[0].NodeType == XmlNodeType.CDATA) //如果第一个子节点是CDATA,则将其内容作为TreeNode的Tag
{
Dictionary<string, string> dict = new Dictionary<string, string>();
dict["tag"] = xmlnode.ChildNodes[0].Value;
treenode.Tag = dict;
if (dict["tag"].Equals("root"))
{
treenode.ImageIndex = 0;
treenode.SelectedImageIndex = 0;
}
else if (dict["tag"].Equals("area"))
{
treenode.ImageIndex = 1;
treenode.SelectedImageIndex = 1;
}
else if (dict["tag"].Equals("user"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
else if (dict["tag"].Equals("lowest"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
}
//将新建的TreeNode添加到父TreeNode的Nodes 集合中
XmlNode2TreeNode(xmlnode.ChildNodes, treenode.Nodes);
}
//将新建的TreeNode添加到TreeView的节点集合中
treeNode.Add(treenode);
}
}
这样就可以在鼠标事件中正确获取节点的级别了,同时也保留了使用Dictionary实例来存储节点信息的功能。
private void XmlNode2TreeNode(XmlNodeList xmlNodeList, TreeNodeCollection treeNodeCollection)
{
foreach (XmlNode xmlNode in xmlNodeList)
{
if (xmlNode.NodeType != XmlNodeType.Element) continue;
var treeNode = new TreeNode {Text = xmlNode.Attributes["Title"].Value};
if (xmlNode.HasChildNodes)
{
if (xmlNode.ChildNodes[].NodeType == XmlNodeType.CDATA)
{
var tagData = new Dictionary<string, string>
{
["tag"] = xmlNode.ChildNodes[].Value
};
treeNode.Tag = tagData;
}
XmlNode2TreeNode(xmlNode.ChildNodes, treeNode.Nodes);
}
treeNodeCollection.Add(treeNode);
}
}
回答引用ChatGPT:
从你的代码中可以看出,在读取XML并将其转换为TreeNode时,你尝试将一个Dictionary<string, string>对象赋给TreeNode的Tag属性。由于TreeNode的Tag属性是object类型,因此你可以将任何对象赋给它。但是,在尝试将一个Dictionary<string, string>对象赋给Tag属性时,你实际上赋给了所有TreeNode节点共同的一个对象,而不是每个节点都有自己的Dictionary对象。
在鼠标事件处理程序中,你尝试获取被点击节点的Tag属性并将其转换为Dictionary<string, string>对象。由于所有的节点共享同一个Dictionary对象,因此你实际上获得的是被最后一个读取的XML节点所对应的Dictionary对象,而不是被点击的节点所对应的Dictionary对象。
解决这个问题的一种方法是,在读取XML并将其转换为TreeNode时,为每个节点创建一个新的Dictionary<string, string>对象,并将该对象赋给TreeNode的Tag属性。修改 XmlNode2TreeNode 方法如下:
private void XmlNode2TreeNode(XmlNodeList xmlNode, TreeNodeCollection treeNode)
{
foreach (XmlNode xmlnode in xmlNode)
{
if (xmlnode.NodeType != XmlNodeType.Element) //忽略非Element类型的节点
{
continue;
}
TreeNode treenode = new TreeNode(); //新建一个TreeNode,并根据XML节点的Title属性设置文本
treenode.Text = xmlnode.Attributes["Title"].Value;
if (xmlnode.HasChildNodes) //如果XML节点有子节点,则递归调用XmlNode2TreeNode方法转换子节点
{
if (xmlnode.ChildNodes[0].NodeType == XmlNodeType.CDATA) //如果第一个子节点是CDATA,则将其内容作为TreeNode的Tag
{
Dictionary<string, string> dict = new Dictionary<string, string>();
dict["tag"] = xmlnode.ChildNodes[0].Value;
treenode.Tag = dict;
if (dict["tag"].Equals("root"))
{
treenode.ImageIndex = 0;
treenode.SelectedImageIndex = 0;
}
else if (dict["tag"].Equals("area"))
{
treenode.ImageIndex = 1;
treenode.SelectedImageIndex = 1;
}
else if (dict["tag"].Equals("user"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
else if (dict["tag"].Equals("lowest"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
}
//将新建的TreeNode添加到父TreeNode的Nodes 集合中
XmlNode2TreeNode(xmlnode.ChildNodes, treenode.Nodes);
}
//将新建的TreeNode添加到TreeView的节点集合中
treeNode.Add(treenode);
}
}
在鼠标事件处理程序中,你现在可以像下面这样获取被点击节点的Dictionary对象:
private void treeView1_MouseUp(object sender, MouseEventArgs e)
{
try
{
Point mpt = new Point(e.X, e.Y);
TreeNode TreeClickNode = this.treeView1.GetNodeAt(mpt);
获取了被点击的节点后,可以通过 Tag 属性获取该节点的 Dictionary 对象,方法如下:
if (TreeClickNode != null)
{
Dictionary<string, string> dict = TreeClickNode.Tag as Dictionary<string, string>;
if (dict != null)
{
// 处理获取到的字典对象
}
}
在上面的代码中,我们首先检查 TreeClickNode 是否为空,以确保用户在单击节点之前没有取消选定任何节点。然后,我们从被点击节点的 Tag 属性中检索出 Dictionary 对象,并将其转换为正确的类型。如果 Tag 属性不包含 Dictionary 对象,则 dict 变量将为 null,并且我们可以相应地处理它。
获取到 dict 对象后,就可以根据需要进行处理了,例如读取其中的键值对、修改字典内容等操作。
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
首先,您使用字典 Dictionary<string, string> dict
存储节点属性,并将其赋值给了 TreeNode.Tag
,您使用字典作为节点属性的目的是为了存储更复杂的节点属性。但是,如果只需存储级别等简单属性,您可以尝试将级别字符串直接赋值给 TreeNode.Tag
,而不使用字典。
其次,您的代码中只在第一个条件分支中为 treenode
分配了 Tag
属性。如果 HasChildNodes
为 false
,则 Tag
将保持 null
。您可以将else分支添加到if语句中,并分配空字典来解决该问题。
最后,您的 CreateMenu
方法应该依据传递给它的字符串来动态创建菜单项。您可以在这个方法里处理菜单点击事件。下面是修改过的代码示例:
private void XmlNode2TreeNode(XmlNodeList xmlNode, TreeNodeCollection treeNode)
{
foreach (XmlNode xmlnode in xmlNode)
{
if (xmlnode.NodeType != XmlNodeType.Element)
{
continue;
}
TreeNode treenode = new TreeNode();
treenode.Text = xmlnode.Attributes["Title"].Value;
// 添加 else 分支,分配空字典
if (xmlnode.HasChildNodes)
{
if (xmlnode.ChildNodes[0].NodeType == XmlNodeType.CDATA)
{
// 将级别字符串赋值给 TreeNode.Tag
treenode.Tag = xmlnode.ChildNodes[0].Value;
if (treenode.Tag.ToString().Equals("root"))
{
treenode.ImageIndex = 0;
treenode.SelectedImageIndex = 0;
treenode.Expand();
}
else if (treenode.Tag.ToString().Equals("area"))
{
treenode.ImageIndex = 1;
treenode.SelectedImageIndex = 1;
}
else if (treenode.Tag.ToString().Equals("user") || treenode.Tag.ToString().Equals("lowest"))
{
treenode.ImageIndex = 2;
treenode.SelectedImageIndex = 2;
}
}
else
{
// 添加 else 分支,分配空字典
treenode.Tag = new Dictionary<string, string>();
}
XmlNode2TreeNode(xmlnode.ChildNodes, treenode.Nodes);
}
treeNode.Add(treenode);
}
}
private void treeView1_MouseUp(object sender, MouseEventArgs e)
{
try
{
Point mpt = new Point(e.X, e.Y);
TreeNode TreeClickNode = this.treeView1.GetNodeAt(mpt);
if (TreeClickNode != null)
{
string tag = TreeClickNode.Tag.ToString();
CreatMenu(tag);
// 处理菜单项点击事件
}
else
{
contextMenuStrip.Items.Clear();
}
}
catch
{
}
}
希望能帮助到您。
如果我的回答解决了您的问题,请采纳!
该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
根据您提供的代码和描述,我认为问题可能是在XmlNode2TreeNode方法中,使用了相同的Dictionary<string, string>对象来为每个TreeNode分配Tag值。由于在分配给TreeNode之前,每个子节点都会将其数据存储在字典中,因此在字典中只会留下最后一次赋值,即最后一个子节点的数据。因此,当您在单击鼠标时检索TreeNode.Tag时,您将获得相同的数据,这将是最后一个子节点的数据。
要解决此问题,您可以为每个子节点创建一个新的Dictionary<string, string>对象,以便在每个子节点之间保留不同的数据。在XmlNode2TreeNode方法中,您可以像下面这样修改代码:
private void XmlNode2TreeNode(XmlNodeList xmlNode, TreeNodeCollection treeNode)
{
foreach (XmlNode xmlnode in xmlNode)
{
if (xmlnode.NodeType != XmlNodeType.Element) //忽略非Element类型的节点
{
continue;
}
TreeNode treenode = new TreeNode(); //新建一个TreeNode,并根据XML节点的Title属性设置文本
treenode.Text = xmlnode.Attributes["Title"].Value;
if (xmlnode.HasChildNodes) //如果XML节点有子节点,则递归调用XmlNode2TreeNode方法转换子节点
{
foreach (XmlNode childnode in xmlnode.ChildNodes)
{
if (childnode.NodeType == XmlNodeType.Element)
{
if (childnode.FirstChild != null && childnode.FirstChild.NodeType == XmlNodeType.CDATA)
{
var dict = new Dictionary<string, string>();
dict["tag"] = childnode.FirstChild.Value;
var childnode_treenode = new TreeNode();
childnode_treenode.Text = childnode.Attributes["Title"].Value;
childnode_treenode.Tag = dict;
if (dict["tag"].Equals("root"))
{
childnode_treenode.ImageIndex = 0;
childnode_treenode.SelectedImageIndex = 0;
childnode_treenode.Expand();
}
else if (dict["tag"].Equals("area"))
{
childnode_treenode.ImageIndex = 1;
childnode_treenode.SelectedImageIndex = 1;
}
else if (dict["tag"].Equals("user") || dict["tag"].Equals("lowest"))
{
childnode_treenode.ImageIndex = 2;
childnode_treenode.SelectedImageIndex = 2;
}
treenode.Nodes.Add(childnode_treenode);
XmlNode2TreeNode(childnode.ChildNodes, childnode_treenode.Nodes);
}
}
}
}
//将新建的TreeNode添加到TreeView的节点集合中
treeNode.Add(treenode);
}
}
在这个修改后的代码中,我们遍历每个子节点,并为每个子节点创建一个新的Dictionary<string, string>对象。我们在新的TreeNode实例中分配这些数据,并将该节点添加到其父节点的Nodes集合中。最后,我们递归调用XmlNode2TreeNode方法,以便为每个子节点设置其子节点。
如果以上回答对您有所帮助,点击一下采纳该答案~谢谢
你可以直接定义TreeNode的key是xpath直接联动起来
代码有点长,如果确有需要,发我完整工程,可代为调试。