树视图控件,从最大值中获取下一个可用节点名称

Tree view control, get next available node name from the max value

我正在研究一种方法,如果存在具有指定名称的节点,它会给出下一个可用节点名称。但思路是该方法从最大值开始给出下一个,例如:

如果我添加一个名为“test”的新节点,该方法应该return“test6”而不是“test2”。包含数字作为名称的节点也会发生同样的情况:

如果我添加一个名为“20”的新节点,下一个可用名称应该是“31”。

所以我的想法是从序列中获取“最大值”并将其加一。这个树节点很容易包含超过500个节点,因此该方法的优化非常重要。我一直在尝试使用此代码执行此操作,但没有按预期工作:

internal static string GetNextAvailableName(TreeView treeView, string searchFor)
{
    //Check if item exists
    if (NodeExistsInSection(treeView, searchFor))
    {
        return searchFor;
    }
    else
    {
        //Initialize variables
        string nextAvailableName = searchFor;
        int counter = 0;

        Match result = Regex.Match(searchFor, @"\d+$", RegexOptions.RightToLeft);
        if (result.Success)
        {
            counter = int.Parse(result.Value);
            if (searchFor.Length >= result.Value.Length)
            {
                searchFor = searchFor.Substring(0, (searchFor.Length - result.Value.Length));
            }
        }


        while (SearchRecByText(treeView, nextAvailableName) != null)
        {
            counter++;
            nextAvailableName = string.Join("", searchFor, counter);
        }

        return nextAvailableName;
    }
}

internal static bool NodeExistsInSection(TreeView treeView, string searchFor)
{
    bool nodeExists = false;

    // Print each node recursively.  
    foreach (TreeNode n in treeView.Nodes)
    {
        //recursiveTotalNodes++;
        if (LoopNodesRecursive(n, searchFor) != null)
        {
            nodeExists = true;
            break;
        }
    }

    return nodeExists;
}

internal static TreeNode SearchRecByText(TreeView treeView, string searchFor)
{
    TreeNode matchedNode = null;

    // Print each node recursively.  
    foreach (TreeNode n in treeView.Nodes)
    {
        //recursiveTotalNodes++;
        matchedNode = LoopNodesRecursive(n, searchFor);
        if (matchedNode != null)
        {
            break;
        }
    }

    return matchedNode;
}

private static TreeNode LoopNodesRecursive(TreeNode treeNode, string searchFor)
{
    // Visit each node recursively.  
    foreach (TreeNode tn in treeNode.Nodes)
    {
        if (tn.Text.Equals(searchFor, StringComparison.OrdinalIgnoreCase))
        {
            return tn;
        }
    }
    return null;
}

如果性能是您的直接目标,我想我会有一个字典跟踪树节点,如果用户输入一个数字,则有一个特殊情况。从发布的代码看来,节点必须在整个树中唯一命名。因此,我会在 tree init 上构建一个字典并在我去的时候维护它

下面是根据用户输入的内容建议新节点名称的方法:

Dictionary<string, int> prefixes = new();

string GetNodeName(string prefix){

    //strip trailing numbers entered by the user
    prefix = Regex.Replace(prefix, "\d+$", "");

    //have we seen the prefix before?
    var n = prefixes.GetValueOrDefault(prefix, 0);

    prefixes[prefix] = n + 1;

    if(n > 0) //nth time we saw it, return number suffix 
      return prefix+n;
    if(prefix == "") //user entered just a number, for the first time
      return "1";
    return prefix; //user entered a new prefix 
    
}

GetNodeName 通过剥离尾随数字并检查生成的前缀的下一个已知数字来识别用户键入的前缀文本。如果前缀未知,它会得到 0,然后将 1 添加为下一个数字,并且 0 是“没有数字后缀”的特殊情况


如果我们需要从某个地方恢复树,我们需要建立我们在构建时看到的 max+1 值:

 void Build(string nodename){

    //strip trailing numbers
    var prefix = Regex.Replace(prefix, "\d+$", "");

    //get the number off the end. Uses c# 8 ranges; if your c# version is less, use Remove(length) instead
    var number = int.Parse(nodename[prefix.Length..]);

    //have we seen the prefix before?
    var n = prefixes.GetValueOrDefault(prefix, 0);

    //node number is higher than dictionary? Bump dict 
    if(number >= n)
      prefixes[prefix] = number + 1;
}

当您从数据库或其他任何东西重建您的树时,为每个节点文本调用构建;它会将前缀字典中的数字增加到它所看到的+1


我认为允许用户重复输入前缀“test2”是一个逻辑错误,您将创建“test2”、“test21”、test22”的节点 - 我认为前缀是“test” ,用户提供的 2 将被忽略,节点将获得“test”的下一行,即“test7”。如果用户仅输入数字,则此逻辑有效,前缀为“”并相应编号