繁体   English   中英

使用 Linq 和 IComparer 对 ObservableCollection 进行排序

[英]Ordering ObservableCollection with Linq and 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 的新手)

该行的问题在于您尝试使用的OrderBy定义:

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

此方法有两个不同的通用参数: TSourceTKey TSource很明显,它与源IEnumerableTSource相同。 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,但您比较的是字符串。

如果你真的需要自己的排序,你可以使用这个比较器:

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接口通知更改。

暂无
暂无

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

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