Sorting child nodes of a treeview after populating the treeview in c# winforms
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 Text property of nodes (So I think I cant sort them before adding them to the tree view, or if it is possible, since the xml files are big in size I dont want to waste the process). A populated treeview in my program looks like this:
As you can guess I want child nodes to sort like (I dont want HBM\D10 to come after HBM\D1) rather I want:
HBM\D1
HBM\D2
HBM\D3
etc...
I have already tried treeView1.Sort() and also adding beginUpdate and endUpdate but I had no suceess :(
I am using .NET 4, any tips would be appriciated
ok I sortet it out using Thomas's advice:
class NodeSorter : IComparer
{
public int Compare(object x, object y)
{
TreeNode tx = (TreeNode)x;
TreeNode ty = (TreeNode)y;
if (tx.Text.Length < ty.Text.Length)
{
return -1;
}
if (tx.Text.Length > ty.Text.Length)
{
return 1;
}
return 0;
开发者_如何学JAVA }
}
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();
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.
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);
}
}
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();
精彩评论