I am having trouble sorting child nodes of a treeview in my winforms program. My treeview is populated by some XML files and it uses an internal text inside the xml files as
I've written some custom comparers to make creating the comparer you need here somewhat easier to do: MultiComparer
and ProjectionComparer
. Together, you could create a comparer to sort what you need on the fly without having to create a class by hand. What I provide here isn't actually how I have the classes written, I trimmed off a lot of code for brevity (though left some helpers to be easier to use).
To create the comparer:
var comparer = OrderedComparer.Create(
ProjectionComparer.Create((TreeNode tn) => tn.Text.Substring(0, 1)),
ProjectionComparer.Create((TreeNode tn) => Convert.ToInt32(tn.Text.Substring(1)))
);
treeView.TreeViewNodeSorter = comparer;
And the classes:
public static class OrderedComparer
{
public static OrderedComparer<TSource> Create<TSource>(params IComparer<TSource>[] comparers)
{ return new OrderedComparer<TSource>(comparers); }
}
public static class ProjectionComparer
{
public static ProjectionComparer<TSource, TKey> Create<TSource, TKey>(Func<TSource, TKey> keySelector)
{ return new ProjectionComparer<TSource, TKey>(keySelector); }
}
public sealed class OrderedComparer<TSource> : Comparer<TSource>
{
public OrderedComparer(params IComparer<TSource>[] comparers)
{
this.comparers = comparers.ToArray();
}
private IComparer<TSource>[] comparers;
public override int Compare(TSource x, TSource y)
{
var cmp = 0;
foreach (var comparer in comparers)
if ((cmp = comparer.Compare(x, y)) != 0)
break;
return cmp;
}
}
public sealed class ProjectionComparer<TSource, TKey> : Comparer<TSource>
{
public ProjectionComparer(Func<TSource, TKey> keySelector)
{
this.keySelector = keySelector;
this.keyComparer = Comparer<TKey>.Default;
}
private Func<TSource, TKey> keySelector;
private IComparer<TKey> keyComparer;
public override int Compare(TSource x, TSource y)
{
var xKey = keySelector(x);
var yKey = keySelector(y);
return keyComparer.Compare(xKey, yKey);
}
}
You're using alphabetic sorting, so D10 comes after D1.
You should try to sort discarding "D" char and converting the rest of string to a number.
Following is the solution I have used in my current project.
public class NodeSorter : IComparer
{
public int Compare(object x, object y)
{
TreeNode tx = x as TreeNode;
TreeNode ty = y as TreeNode;
if (tx.Name== null || ty.Name== null)
return 0;
return (-1) * string.Compare(tx.Name.ToString(), ty.Name.ToString());
}
}
tvListofItems.TreeViewNodeSorter = new NodeSorter();
tvListofItems.Sort();
You need to create a custom comparer and assign it to the TreeViewNodeSorter
property:
public class NodeSorter : System.Collections.IComparer
{
public int Compare(object x, object y)
{
TreeNode tx = (TreeNode)x;
TreeNode ty = (TreeNode)y;
// Your sorting logic here... return -1 if tx < ty, 1 if tx > ty, 0 otherwise
...
}
}
...
treeView.TreeViewNodeSorter = new NodeSorter();
treeView.Sort();