Сортировка дочерних узлов treeview после заполнения treeview в c # winforms

#c# #winforms #sorting #treeview

#c# #winforms #сортировка #treeview

Вопрос:

У меня возникли проблемы с сортировкой дочерних узлов treeview в моей программе winforms. Мой treeview заполнен некоторыми XML-файлами и использует внутренний текст внутри xml-файлов в качестве текстового свойства узлов (поэтому я думаю, что не могу отсортировать их перед добавлением в древовидное представление, или, если это возможно, поскольку xml-файлы большого размера, я не хочу тратить процесс впустую). Заполненный treeview в моей программе выглядит следующим образом:

введите описание изображения здесь

Как вы можете догадаться, я хочу, чтобы дочерние узлы сортировались следующим образом (я не хочу, чтобы HBM D10 следовал за HBM D1), скорее я хочу:

     HBMD1
    HBMD2
    HBMD3
etc...
  

Я уже пробовал treeView1.Sort(), а также добавление BeginUpdate и EndUpdate, но у меня не было успеха: (

Я использую .NET 4, любые советы будут оценены

хорошо, я сортирую это, используя совет Томаса:

     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;
        } 
}
  

Ответ №1:

Вам нужно создать пользовательский компаратор и присвоить его 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();
  

Комментарии:

1. Спасибо, не могли бы вы рассказать немного больше о логической части? речь идет о преобразовании узлов в двоичный файл или что-то в этом роде?

2. @Sean87, вам нужно выполнить сортировку по тексту TreeNode в соответствии с вашей собственной логикой, т. Е. извлечь числовую часть текста и сравнить по номеру, если остальная часть имени равна

3. Для того, чтобы это работало в .net 4 (Windows 8), мне пришлось сделать его наследуемым от Comparer<TreeNode> и реализовать Compare как public override int Compare(TreeNode Node1, TreeNode Node2)

4. @ThunderGr, для этого нет причин. Даже в .NET 4.5 TreeViewNodeSorter свойством является till типа IComparer , а не IComparer<T> . Я подозреваю, что вам просто не хватало импорта пространства имен… Опубликованный мной код работает с .NET 4.x таким же образом, как и с более ранними версиями.

5. @ThunderGr, я исправил код, чтобы явно указывать пространство имен

Ответ №2:

Вы используете алфавитную сортировку, поэтому D10 идет после D1.
Вам следует попробовать выполнить сортировку, отбросив символ «D» и преобразовав оставшуюся часть строки в число.

Ответ №3:

Я написал несколько пользовательских средств сравнения, чтобы несколько упростить создание нужного вам здесь средства сравнения: MultiComparer и ProjectionComparer . Вместе вы могли бы создать средство сравнения для сортировки того, что вам нужно «на лету», без необходимости создавать класс вручную. То, что я предоставляю здесь, на самом деле не так, как у меня написаны классы, я урезал много кода для краткости (хотя оставил некоторые помощники для упрощения использования).

Для создания средства сравнения:

 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>.Defau<
    }
    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);
    }
}
  

Комментарии:

1. Обновлено до более поздней версии кода (все еще несколько урезано).

Ответ №4:

Ниже приведено решение, которое я использовал в своем текущем проекте.

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