在c#winforms中填充树视图后对树视图的子节点进行排序

在c#winforms中填充树视图后对树视图的子节点进行排序,c#,winforms,sorting,treeview,C#,Winforms,Sorting,Treeview,我在winforms程序中对treeview的子节点进行排序时遇到问题。我的treeview由一些XML文件填充,它使用XML文件中的内部文本作为节点的文本属性(因此我认为在将它们添加到树视图之前,我无法对它们进行排序,或者如果可能的话,因为XML文件很大,我不想浪费这个过程)。我的程序中填充的树视图如下所示: 您可以猜到,我希望子节点按如下顺序排序(我不希望HBM\D10位于HBM\D1之后),而希望: HBM\D1 HBM\D2 HBM\D3 etc... 我已经

我在winforms程序中对treeview的子节点进行排序时遇到问题。我的treeview由一些XML文件填充,它使用XML文件中的内部文本作为节点的文本属性(因此我认为在将它们添加到树视图之前,我无法对它们进行排序,或者如果可能的话,因为XML文件很大,我不想浪费这个过程)。我的程序中填充的树视图如下所示:

您可以猜到,我希望子节点按如下顺序排序(我不希望HBM\D10位于HBM\D1之后),而希望:

    HBM\D1
    HBM\D2
    HBM\D3
etc...
我已经尝试过treeView1.Sort()并添加了beginUpdate和endUpdate,但没有成功:(

我使用的是.NET4,任何提示都将不胜感激

好的,我按照托马斯的建议分类:

    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;
        } 
}
类节点排序器:IComparer
{
公共整数比较(对象x、对象y)
{         
TreeNode tx=(TreeNode)x;
TreeNode ty=(TreeNode)y;
如果(tx.Text.Lengthty.Text.Length)
{
返回1;
}
返回0;
} 
}

您使用的是字母排序,因此D10位于D1之后。

您应该尝试对丢弃的“D”字符进行排序,并将字符串的其余部分转换为数字。

您需要创建一个自定义比较器,并将其分配给
TreeViewNodeSorter
属性:

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();
公共类节点排序器:System.Collections.IComparer
{
公共整数比较(对象x、对象y)
{
TreeNode tx=(TreeNode)x;
TreeNode ty=(TreeNode)y;
//这里的排序逻辑…如果txty,则返回1;否则返回0
...
}
}
...
treeView.TreeViewNodeSorter=新节点排序器();
treeView.Sort();

我编写了一些自定义比较器,使您在这里创建所需的比较器变得更容易:
MultiComparer
projectoncomparer
。您可以一起创建一个比较器来对需要的内容进行排序,而无需手动创建类。我在这里提供的实际上不是如何创建类在写这篇文章时,为了简洁起见,我删掉了很多代码(尽管留下了一些帮助程序,以便更容易使用)

要创建比较器,请执行以下操作:

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;
课程包括:

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);
    }
}
公共静态类OrderedComparer
{
公共静态OrderedComparer创建(参数IComparer[]比较器)
{返回新的OrderedComparer(comparers);}
}
公共静态类ProjectOnComparer
{
公共静态项目比较程序创建(Func键选择器)
{返回新的ProjectOnComparer(keySelector);}
}
公共密封类OrderedComparer:Comparer
{
公共排序比较器(参数IComparer[]比较器)
{
this.comparers=comparers.ToArray();
}
私人IComparer[]比较器;
公共覆盖int比较(TSource x,TSource y)
{
var-cmp=0;
foreach(比较器中的var比较器)
如果((cmp=comparer.Compare(x,y))!=0)
打破
返回cmp;
}
}
公共密封类项目比较程序:比较程序
{
公共项目比较人(Func keySelector)
{
this.keySelector=keySelector;
this.keycomarer=Comparer.Default;
}
专用Func键选择器;
私有i比较键比较器;
公共覆盖int比较(TSource x,TSource y)
{
var xKey=键选择器(x);
var yKey=键选择器(y);
返回keycomarer.Compare(xKey,yKey);
}
}

以下是我在当前项目中使用的解决方案

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();              

谢谢,你介意再多介绍一下逻辑部分吗?它是关于将节点转换为二进制还是什么的?@Sean87,你需要根据自己的逻辑按树节点的文本排序,即提取文本的数字部分,如果名称的其余部分相等,则按数字进行比较,以便在.net 4(Windows 8)上运行我必须让它从Comparer继承并实现Compare as
public override int Compare(TreeNode Node1,TreeNode Node2)
@ThunderGr,没有理由这么做。即使在.NET 4.5中,
TreeViewNodeSorter
属性的类型仍然是
IComparer
,而不是
IComparer
。我怀疑您只是缺少了名称空间导入…我发布的代码与.NET 4.x的早期版本的工作方式相同。@ThunderGr,我将代码修复为specify名称空间已明确更新为代码的最新版本(仍有一些修改)。