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