Упорядочение ObservableCollection с Linq и IComparer
Я хочу заказать ObservableCollection в алфавитном порядке, потому что мне не нужно создавать другую привязку. Я видел, что мы могли бы использовать Linq и метод OrderBy. Я также хотел бы использовать персонального IComparer, потому что мне придется организовывать сложные данные (списки в другие списки), но VS говорит мне, что я не могу использовать свой собственный компаратор:
(дать вам ссылку на ошибку, потому что мой VS на французском языке)
http://msdn.microsoft.com/en-gb/library/hxfhx4sy%28v=vs.90%29.aspx
Есть идеи?
private void SortGraphicObjectsAscending(object sender, RoutedEventArgs e)
{
GraphicObjects.OrderBy(graphicObject => graphicObject.Nom, new GraphicObjectComparer(true));
}
И мой собственный компаратор (который уже проверен)
public class GraphicObjectComparer : IComparer<GraphicObject>
{
int order = 1;
public GraphicObjectComparer(Boolean ascending)
{
if (!ascending)
{
order = -1;
}
}
public GraphicObjectComparer()
{
}
public int Compare(GraphicObject x, GraphicObject y)
{
return String.Compare(x.Nom, y.Nom, false) * order;
}
}
Спасибо за ваши ответы. Во всяком случае у меня есть другая проблема. Как сказал Майкл, я использую более сложный компаратор, но для другого объекта. Эта сущность отображается с иерархическим деревом, и объект может содержать список других объектов того же типа.
Я не смог протестировать свой GraphicObject, потому что у меня нет доступа к БД (в данный момент не было объекта). С тестами на моем VideoEntity кажется, что моя ObservableCollection не отсортирована так, как я хочу (я создаю другую). Я хочу изменить это в алфавитном порядке, но это не работает.
public class VideoEntityComparer : IComparer<VideoEntity>
{
int order = 1;
public VideoEntityComparer(Boolean ascending)
{
if (!ascending)
{
this.order = -1; // so descending
}
}
public VideoEntityComparer()
{
}
public int Compare(VideoEntity x, VideoEntity y)
{
if ((x is BaseDirectory && y is BaseDirectory) || (x is BaseSite && y is BaseSite) || (x is VideoEncoder && y is VideoEncoder))
{
return string.Compare(x.Nom, y.Nom, false) * order; // only objects of the same type are sorted alphabetically
}
else if ((x is BaseDirectory && y is BaseSite) || (x is BaseSite && y is VideoEncoder))
{
return -1;
}else
{
return 1;
}
}
}
private void SortDirectoriesDescending(object sender, RoutedEventArgs e)
{
ObservableCollection<BaseDirectory> tempDir = new ObservableCollection<BaseDirectory>(
Directories.OrderBy(directory => directory, new VideoEntityComparer(false)));
Directories = tempDir;
}
PS: кстати, я действую по DependancyProperty. Это правильный способ сделать это? (Я новичок в WPF)
3 ответа
Проблема с этой линией в определении OrderBy
что вы пытаетесь использовать:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IComparer<TKey> comparer
)
У этого метода есть два разных общих параметра: TSource
а также TKey
, TSource
очевидно, это так же, как TSource
для источника IEnumerable
, TKey
Параметр - это тот, который компилятор пытается и не может сделать вывод, потому что вы пытаетесь использовать два разных типа. Ваш звонок:
GraphicObjects.OrderBy(graphicObject => graphicObject.Nom, new GraphicObjectComparer(true));
Ваш первый параметр Func<GraphicObject, string>
но ваш второй параметр IComparer<GraphicObject>
; это означает, что вы используете TKey = string
в одном месте и TKey = GraphicObject
в другом.
Первый параметр, Func<>
делегат, является "ключевым селектором"; это как ты говоришь OrderBy
какие значения сортировать. Так как ваш IComparer<>
сортировка на основе всего GraphicObject
Например, это то, что вы должны выбрать в качестве ключа:
GraphicObjects.OrderBy(go => go, new GraphicObjectComparer(true));
Я предполагаю, что ваш пользовательский объект сравнения действительно сложнее, чем вы показали, потому что ваш пример сравнения довольно избыточен:
var asc = GraphicObjects.OrderBy(go => go.Nom);
var desc = GraphicObjects.OrderByDescending(go => go.Nom);
Кроме того, обратите внимание, что ваш пример кода на самом деле ничего не делает с недавно отсортированным списком, поэтому его просто выбрасывают. Операции LINQ никогда не изменяют перечисляемый источник, вместо этого они всегда возвращают новую преобразованную копию.
Ваш comparer
сравнивает GraphicObject
, Так что ваши OrderBy
должно быть
GraphicObjects.OrderBy(graphicObject => graphicObject,
new GraphicObjectComparer(true));
или просто использовать
GraphicObjects.OrderBy(graphicObject => graphicObject.Nom);
КСТАТИ, OrderBy
не сортирует на месте, вы должны назначить возвращаемый IEnumerable<GraphicsObject>
к переменной
Проблема в том, что ваш Comparer использует GraphicObject, но вы сравниваете строки.
Если вам действительно нужен ваш собственный заказ, вы можете использовать этот Comparer:
public class GraphicObjectComparer : IComparer<string>
{
int order = 1;
public GraphicObjectComparer(Boolean ascending)
{
if (!ascending)
{
order = -1;
}
}
public GraphicObjectComparer()
{
}
public int Compare(string x, string y)
{
return String.Compare(x, y, false) * order;
}
}
Или вы предоставляете GraphicObject для вашего компаратора, а не строку.
Чтобы отсортированный ObservableCollection отражал все изменения в исходной коллекции, вы можете использовать мою библиотеку ObservableComputations. Используя эту библиотеку, вы можете написать такой код:
var sortedGraphicObjects = GraphicObjects.Ordering(
graphicObject => graphicObject.Nom, new GraphicObjectComparer(true));
sortedGraphicObjects является ObservableCollection и отражает все изменения в коллекции GraphicObjects и свойстве Nom. Убедитесь, что свойство Nom уведомляет об изменениях через интерфейс INotifyPropertyChanged.