Click here to Skip to main content
14,326,871 members
Rate this:
Please Sign up or sign in to vote.
See more:
e.g.

Input:

TreeView
|_Node 1
|_Node 10
|_Node 2
|_Node 3

Output:

TreeView
|_Node 1
|_Node 2
|_Node 3
|_Node 10


What I have tried:

folderTreeView.TreeViewNodeSorter = new NodeSorter();
folderTreeView.Sort();


In the class NodeSorter there must be the natural sort of the nodes.
Posted
Updated 9-Sep-19 14:54pm
Comments
BillWoodruff 9-Sep-19 11:43am
   
Need more information: is the number always at the end ? The strings shown here represent the Text Property of WinForm TreeNodes ?
Member 12226991 9-Sep-19 17:50pm
   
The numbers can be anywhere. Basically I need a sort method similar to Natural Sort used in Windows Explorer. As for the second question: yes.
Rate this:
Please Sign up or sign in to vote.

Solution 2

By default the NodeSorter is going to sort strings based upon their values, and is working as designed based on the values that you are showing.
To sort using a different method, you will need to implement or own Compare method; such as is provided by MS Docs; the last block of code in the provided sample
TreeView.TreeViewNodeSorter Property (System.Windows.Forms) | Microsoft Docs[^]
// Create a node sorter that implements the IComparer interface.
public class NodeSorter : IComparer
{
    // Compare the length of the strings, or the strings
    // themselves, if they are the same length.
    public int Compare(object x, object y)
    {
        TreeNode tx = x as TreeNode;
        TreeNode ty = y as TreeNode;

        // Compare the length of the strings, returning the difference.
        if (tx.Text.Length != ty.Text.Length)
            return tx.Text.Length - ty.Text.Length;

        // If they are the same length, call Compare.
        return string.Compare(tx.Text, ty.Text);
    }
}
Now this example is based on what is being done in the rest of the provided example, you will need to write your own specialized implementation based on the values you are expecting.
Perhaps you could use a RegEx or a string/Replace function to remove all the non-numeric characters, cast to an Integer, and then make an appropriate return based on the integers
   
Comments
BillWoodruff 9-Sep-19 18:54pm
   
+5
Rate this:
Please Sign up or sign in to vote.

Solution 1

You need to add your own sort method to modify the order depending on the numbers in the node names. When numbers are sorted as character strings then "10" or "100" will come before "2". Sso you need to convert them to their numerical values and sort accordingly.
   
Rate this:
Please Sign up or sign in to vote.

Solution 3

1 you get these file names from enumerating Directories using ?

2 have you tried using EnumerateFiles method .NET 4 ?

3 have you tried using Linq sorting with OrderBy/Ascending/Descending ?

A more complex way to deal with this is to use a 'SortedDictionary with a custom Comparer: the example shown here exploits the fact that numeric character sequences not at the end of the string are sorted in the order you want; only when the numeric characters are at the start of the string, do you need to compare in "reverse."
public class SortFilesComparer : IComparer<string>
{
    public int Compare(string fname1, string fname2)
    {
        // number at the start of file name 1 ?
        var num1 = fname1.TakeWhile(char.IsDigit);

        if (num1.Count() != 0)
        {
            // number at the start of file name 2 ?
            var num2 = fname2.TakeWhile(char.IsDigit);

            if (num2.Count() != 0)
            {
                // we'll need both string and int
                string n1s = new string(num1.ToArray());
                string n2s = new string(num2.ToArray());

                int n1 = Convert.ToInt32(n1s);
                int n2 = Convert.ToInt32(n2s);

                // voodoo !
                if (n1s.Contains(n2s))
                {
                    if (n1 > n2)
                    {
                        return fname2.CompareTo(fname1);
                    }
                }
                else if (n2s.Contains(n1s))
                {
                    if (n1 < n2)
                    {
                        return fname2.CompareTo(fname1);
                    }
                }
            }
        }

        return fname1.CompareTo(fname2);
    }
}
Usage example:
SortedDictionary<string, string> sd = new SortedDictionary<string, string>(new SortFilesComparer());

sd.Add("234hello", "3");
sd.Add("234567hello", "4");
sd.Add("1234567hello", "4");

sd.Add("hello 1", "2");
sd.Add("hello 10", "1");

sd.Add("100hello", "3");
sd.Add("101hello", "4");

sd.Add("10hello", "3");
sd.Add("1hello", "4");

sd.Add("hell10", "5");
sd.Add("hell1", "6");
Run the code, and examine the elements of 'sd.

Note: this was written quickly, and, while okay with these test values, should be tested thoroughly.

I don't really like how complex this code is, and there is one case this doesn't handle ... can you guess what it is :)
   
v4

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100