简体   繁体   English

使用 Linq 和 IComparer 对 ObservableCollection 进行排序

[英]Ordering ObservableCollection with Linq and IComparer

I want to order alphabetically an ObservableCollection because I don't wanna have to create another binding.我想按字母顺序排列一个 ObservableCollection,因为我不想创建另一个绑定。 I've seen we could use Linq and the method OrderBy.我已经看到我们可以使用 Linq 和 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:我也想使用个人 IComparer 因为我将不得不组织复杂的数据(列表到其他列表),但 VS 告诉我我不能使用我自己的比较器:

(give you the link of the error because my VS is in french) (给你错误的链接因为我的VS是法语的)

http://msdn.microsoft.com/en-gb/library/hxfhx4sy%28v=vs.90%29.aspx 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).我无法测试我的 GraphicObject,因为我无权访问数据库(目前没有对象)。 With the tests on my VideoEntity it seems my ObservableCollection is not sorted the way I want (I create another one).通过对我的 VideoEntity 的测试,我的 ObservableCollection 似乎没有按照我想要的方式排序(我创建了另一个)。 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. PS:顺便说一句,我正在对 DependancyProperty 进行操作。 Is it the correct way to do it?这是正确的方法吗? (I'm new on WPF) (我是 WPF 的新手)

The problem with that line is in the definition of OrderBy that you're trying to use:该行的问题在于您尝试使用的OrderBy定义:

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 .此方法有两个不同的通用参数: TSourceTKey TSource is obvious, it's the same as the TSource for the source IEnumerable . TSource很明显,它与源IEnumerableTSource相同。 The TKey parameter is the one that the compiler is trying, and failing, to infer because you are trying to use two different types. TKey参数是编译器尝试推断但失败的参数,因为您正在尝试使用两种不同的类型。 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> ;您的第一个参数是Func<GraphicObject, string>但您的第二个参数是IComparer<GraphicObject> this means you're using TKey = string in one place and TKey = GraphicObject in the other.这意味着您在一个地方使用TKey = string而在另一个地方使用TKey = GraphicObject

The first parameter, the Func<> delegate, is the "key selector";第一个参数, Func<>委托,是“键选择器”; it's how you tell OrderBy which values to sort by.这就是您告诉OrderBy哪些值要排序的方式。 Since your IComparer<> is sorting based on the entire GraphicObject instance , that's what you should be selecting as your key:由于您的IComparer<>是基于整个GraphicObject实例进行排序的,因此您应该选择它作为键:

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. LINQ 操作永远不会更改可枚举的源,它们总是返回一个新的、转换后的副本。

your comparer compares GraphicObject .你的comparer比较GraphicObject so your OrderBy should be所以你的OrderBy应该是

 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顺便说一句, OrderBy不会就地排序,您应该将返回的IEnumerable<GraphicsObject>分配给一个变量

The problem is that your Comparer uses GraphicObject, but you compare strings.问题是您的 Comparer 使用 GraphicObject,但您比较的是字符串。

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.或者您向比较器提供一个 GraphicObject,而不是字符串。

In order to sorted ObservableCollection reflects all the changes in the source collection you can use my ObservableComputations library.为了排序 ObservableCollection 反映源集合中的所有更改,您可以使用我的ObservableComputations库。 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. sortedGraphicObjects 是 ObservableCollection,反映了 GraphicObjects 集合和 Nom 属性中的所有变化。 Ensure that Nom property notifies of changes through the INotifyPropertyChanged interface.确保 Nom 属性通过INotifyPropertyChanged接口通知更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM