遍历树并在 C# 中获取某些子项

Iterating through a Tree and getting certain children in C#

我目前正在使用这样定义的树结构

public class TreeNode
{
   private ObservableCollection<TreeItem> nodeItems;
   private ObservableCollection<TreeNode> nodeChildren;
   //public "NodeItems" and "NodeChildren" getters and setters
}

public class TreeItem
{
   private bool isSelected;
   private string Name;
   //public "IsSelected" and "Name" getters and setters
}

public class Tree
{
   private TreeNode rootNode;
   //public getters and setters properties
}

我正在尝试编写一个函数或 public 属性 递归地获取 Tree 中具有 isSelected == true 的所有 nodeItems并使其成为平面集合。

所以我在 TreeNode class 中写了这个函数,递归地遍历子节点:

public ObservableCollection<TreeItem> SelectedItems()
    {
        ObservableCollection<TreeItem> tempCollection = new ObservableCollection<TreeItem>();
        if (nodeItems != null)
        {
            foreach (TreeItem item in nodeItems)
            {
                if (item.IsSelected == true)
                {
                    tempCollection.Add(item);
                }
            }
        }
        if (nodeChildren != null)
        {
            foreach (TreeNode node in nodeChildren)
            {
                tempCollection.Concat(node.SelectedItem()); 
            }
        }
        return tempCollection;
    }

但它总是returns最后是一个空集合

我该如何更正它,并可能改进它(通过使用 Lambda 表达式或 属性)?

ObservableCollection 上的 Concat 函数不修改任何参数。您必须将生成的对象分配给您的 tempCollection.

    if (nodeChildren != null)
    {
        foreach (TreeNode node in nodeChildren)
        {
            tempCollection = new ObservableCollection<TreeNode>(tempCollection.Concat(node.SelectedItem())); 
        }
    }

编辑: 或者,您可以使用重载私有方法来不使用那么多临时集合:

public ObservableCollection<TreeItem> SelectedItems()
{
    ObservableCollection<TreeItem> toReturn = new ObservableCollection<TreeItem>();
    SelectedItems(toReturn);
    return toReturn;
}

private void SelectedItems(ObservableCollection<TreeItem> tempCollection)
{
    if (nodeItems != null)
    {
        foreach (TreeItem item in nodeItems)
        {
            if (item.IsSelected == true)
            {
                tempCollection.Add(item);
            }
        }
    }
    if (nodeChildren != null)
    {
        foreach (TreeNode node in nodeChildren)
        {
            node.SelectedItems(tempCollection);
        }
    }
}

您可以将树的定义简化为:

public class Tree : ObservableCollection<Tree>
{
    public ObservableCollection<TreeItem> nodeItems;
}

现在您可以这样做了:

public IEnumerable<TreeItem> FlattenIsSelected(Tree tree)
{
    return tree.nodeItems.Where(x => x.isSelected)
        .Concat(tree.SelectMany(t => FlattenIsSelected(t)));
}

如果您保持当前的定义,这并不困难。