【问题标题】:TreeNodeCollection reference problemTreeNodeCollection 参考问题
【发布时间】:2011-01-20 13:09:47
【问题描述】:

首先我们有万能的代码!

List nodes = new List();
TreeNode Temp = new TreeNode();

TreeNodeCollection nodeList = treeViewTab4DirectoryTree.Nodes;

while (nodeList.Count != 0)
{
    Temp = nodeList[0];

    while (Temp.FirstNode != null)
    {
        Temp = Temp.FirstNode;
    }

    if (!nodes.Contains(Temp.FullPath))
    {
        nodes.Add(Temp.Text);
    }

    nodeList.Remove(Temp);
}

现在的问题是:我编写了上面的代码,目的是创建一个包含树中所有节点的文本的列表。这很完美。我遇到的问题是,当我从变量中删除节点时,它们也会从实际列表中删除。问题是如何制作节点列表的副本,这样我就可以在不弄乱 ACTUAL 列表的情况下使用它们。如何在不引用它的情况下复制它?任何帮助将不胜感激!

【问题讨论】:

  • 仅供参考:在第 2 行,您无需创建新的 TreeNode —— 您只需分配变量 null 即可。
  • @Jon 谢谢。我已经对我的代码进行了更改
  • 这是标准的 WinForms TreeView 吗?当然,您一定打算使用: List nodes = new List(); ? ...也无需将 'Temp 初始化为任何内容:您可以使用:TreeNode Temp;
  • 如果您在标准 WinForms Treeview 上进行迭代,您可能会发现此处使用 Linq 的讨论和示例代码很有价值:stackoverflow.com/questions/1815497/…

标签: c# .net treeview treenode


【解决方案1】:

出现您的问题是因为“nodeList”是对 treeViewTab4DirectoryTree.Nodes 的引用,而不是它的副本。

解决方案完全取决于您使用的 TreeNodeCollection 类型(WinForms、ASP.net 还是其他?),因为您需要查找 .Copy()、.Clone()、.ToArray () 方法或类似方法获取集合内容的副本,而不是对现有集合的引用。

例如,如果您使用的是 asp.net 和 System.Web.UI.WebControls.TreeNodeCollection,您可以以类似于以下方式使用 .CopyTo 方法:

TreeNode[] x = null;
treeViewTab4DirectoryTree.Nodes.CopyTo(x, 0);

【讨论】:

  • @Rob 我试过你的代码,但编译器告诉你目标数组不能为空,也不能取消分配。有没有办法让它动态化?如果 CopyTo 的签名特别需要一个数组,列表是否有效?
  • @Adkins,您可能必须在使用它之前初始化数组,具体细节将取决于您正在使用的 TreeNode 类型。从本质上讲,我的回答的重点是您需要创建一个 new 集合以从中删除项目,而不是从 nodeList 或 treeViewTab4DirectoryTree.Nodes 中删除它们。相反,您是否可以有一个 List添加要保留的节点(或要删除的节点),而不是尝试修改现有集合?
  • 我无法在 TreeNodeCollection 类型和 TreeNode 元素集合之间进行隐式转换(?嗯?)。但是,我可以通过 TreeNodeCollection foreach 将每一个添加到 TreeNode 的集合中。谢谢指点!
【解决方案2】:

更新为显示基于堆栈的方法:

List<String> result = new List<String>();
Stack<IEnumerator> nodeColls = new Stack<IEnumerator>();
IEnumerator nodes = treeViewTab4DirectoryTree.Nodes.GetEnumerator();

nodeColls.Push(null);

while (nodes != null)
{
    while (nodes.MoveNext())
    {
        result.add(nodes.Current.FullPath);
        if (nodes.Current.FirstNode != null)
        {
            nodeColls.Push(nodes);
            nodes = nodes.Current.Nodes.GetEnumerator();
        }
    }

    nodes = nodeColls.Pop();
}

下面的代码不像cmets中提到的那样工作,因为它没有遍历整个树,而只取每个顶级分支的第一个叶子节点。

我实际上认为原始代码(在问题中)也是这样做的,因为我认为 Remove 实际上会在找到它下面的第一个叶节点后删除顶层节点;但是,它会尝试从顶级节点集合中删除叶节点,如果找不到则忽略它。

原帖,无效代码

首先,为什么需要从列表中删除项目?

List<string> nodes = new List<string>();

foreach (TreeNode tn in treeViewTab4DirectoryTree.Nodes)
{
    TreeNode temp = tn;

    while (Temp.FirstNode != null)
    {
        Temp = Temp.FirstNode;
    }

    if (!nodes.Contains(Temp.FullPath))
    {
        nodes.Add(Temp.Text);
    }
}

要回答您的具体问题,假设 Nodes 集合实现了 IEnumerable,请使用:

List<TreeNode> nodeList = new List<TreeNode>(treeViewTab4DirectoryTree.Nodes);

如果您决定坚持使用 while 循环,则可以通过更改来保存实例

TreeNode Temp = new TreeNode();

TreeNode Temp = null;

...您从未真正使用过您创建的对象,至少在您显示的部分代码中是这样。

【讨论】:

  • @Arne 我尝试按照您的说法创建一个列表,但收到一个错误,即构造函数获取了不正确的参数。我检查了它,它得到了它想要的东西,但我无法摆脱错误消息。
  • @Arne 您建议的循环也只返回每个根节点的第一个子节点。这就是我删除元素的原因。当我完全循环其中一个时,我将其删除。当没有更多东西可以删除时,我就完成了。
  • @Arne Standard WinForms TreeNodeCollection is not IEnumerable : 讨论使其与 IEnumerable 兼容以及使用 Linq 进行迭代的示例代码:stackoverflow.com/questions/1815497/…
  • @Adkins - 是的,我错过了一个细节 - 你实际上是从根节点集合中删除树中的每个节点,这就是让我失望的原因。我认为我更喜欢基于堆栈的解决方案(或递归),主要是因为下一个阅读代码的人将更容易弄清楚它的作用。将编辑以显示它已通过堆栈完成。
  • @BillW - 实际上,它 IEnumerable,只是不是 IEnumerable
猜你喜欢
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多