Question

I want to order alphabetically an ObservableCollection because I don't wanna have to create another binding. I've seen we could use Linq and the method OrderBy. I would like also to use a personal IComparer because I will have to organize complex datas (lists into other lists), but VS tells me I can't use my own comparer :

(give you the link of the error because my VS is in french)

http://msdn.microsoft.com/en-gb/library/hxfhx4sy%28v=vs.90%29.aspx

Any ideas ?

private void SortGraphicObjectsAscending(object sender, RoutedEventArgs e)
    {
        GraphicObjects.OrderBy(graphicObject => graphicObject.Nom, new GraphicObjectComparer(true));

    }

And my own comparer (which is already tested)

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

}

Thanks for your answers. Anyway I have another problem. As Michael said, I use a more complex comparer but for another entity. This entity is displayed with a hierarchical tree, and an object might contain a list of other objects of the same type.

I couldn't test an my GraphicObject becuse I don't have access to the DB (there was no object at the moment). With the tests on my VideoEntity it seems my ObservableCollection is not sorted the way I want (I create another one). I want to reverse it alphabetically but it doesn't work.

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 : by the way, I'm acting on a DependancyProperty. Is it the correct way to do it ? (I'm new on WPF)

Was it helpful?

Solution

The problem with that line is in the definition of OrderBy that you're trying to use:

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    IComparer<TKey> comparer
)

There are two different generic parameters to this method: TSource and TKey. TSource is obvious, it's the same as the TSource for the source IEnumerable. The TKey parameter is the one that the compiler is trying, and failing, to infer because you are trying to use two different types. Your call:

GraphicObjects.OrderBy(graphicObject => graphicObject.Nom, new GraphicObjectComparer(true));

Your first parameter is a Func<GraphicObject, string> but your second parameter is an IComparer<GraphicObject>; this means you're using TKey = string in one place and TKey = GraphicObject in the other.

The first parameter, the Func<> delegate, is the "key selector"; it's how you tell OrderBy which values to sort by. Since your IComparer<> is sorting based on the entire GraphicObject instance, that's what you should be selecting as your key:

GraphicObjects.OrderBy(go => go, new GraphicObjectComparer(true));

I'm assuming that your custom comparer object is actually more complex than what you've shown, because your sample comparer is pretty redundant:

var asc = GraphicObjects.OrderBy(go => go.Nom);
var desc = GraphicObjects.OrderByDescending(go => go.Nom);

Also, note that you're sample code isn't actually doing anything with the newly-sorted list, so it's just getting thrown out. LINQ operations never change the source enumerable, they always return a new, transformed copy of it instead.

OTHER TIPS

your comparer compares GraphicObject. so your OrderBy should be

 GraphicObjects.OrderBy(graphicObject => graphicObject,
                                                 new GraphicObjectComparer(true));

or just use

GraphicObjects.OrderBy(graphicObject => graphicObject.Nom);

BTW, OrderBy doesn't sort in-place, you should assign the returned IEnumerable<GraphicsObject> to a variable

The problem is that your Comparer uses GraphicObject, but you compare strings.

If you really need your own ordering, you can use this 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;
    }
}

Or you provide a GraphicObject to your comparer, not a string.

In order to sorted ObservableCollection reflects all the changes in the source collection you can use my ObservableComputations library. Using this library you can code like this:

var sortedGraphicObjects = GraphicObjects.Ordering(
    graphicObject => graphicObject.Nom, new GraphicObjectComparer(true));

sortedGraphicObjects is ObservableCollection and reflects all the changes in the GraphicObjects collection and Nom property. Ensure that Nom property notifies of changes through the INotifyPropertyChanged interface.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top