【问题标题】:Ordering ObservableCollection with Linq and IComparer使用 Linq 和 IComparer 订购 ObservableCollection
【发布时间】:2012-07-25 16:00:04
【问题描述】:

我想按字母顺序排列 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 新手)

【问题讨论】:

    标签: c# linq sql-order-by icomparer


    【解决方案1】:

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

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

    此方法有两个不同的通用参数:TSourceTKeyTSource 很明显,它与源 IEnumerableTSource 相同。 TKey 参数是编译器尝试但失败的参数,因为您尝试使用两种不同的类型。您的来电:

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

    您的第一个参数是Func&lt;GraphicObject, string&gt;,但您的第二个参数是IComparer&lt;GraphicObject&gt;;这意味着您在一处使用TKey = string,在另一处使用TKey = GraphicObject

    第一个参数,Func&lt;&gt; 委托,是“键选择器”;这就是您告诉OrderBy 要排序的值的方式。由于您的IComparer&lt;&gt; 是基于整个GraphicObject 实例 进行排序的,因此您应该选择它作为您的键:

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

    我假设您的自定义比较器对象实际上比您显示的更复杂,因为您的示例比较器非常多余:

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

    另外,请注意,您的示例代码实际上并没有对新排序的列表做任何事情,所以它只是被扔掉了。 LINQ 操作从不更改源可枚举,它们总是返回一个新的、转换后的副本。

    【讨论】:

      【解决方案2】:

      您的comparerGraphicObject 进行比较。所以你的OrderBy 应该是

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

      或者直接使用

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

      顺便说一句,OrderBy 不会就地排序,您应该将返回的 IEnumerable&lt;GraphicsObject&gt; 分配给一个变量

      【讨论】:

        【解决方案3】:

        问题是您的比较器使用的是 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 给你的比较器,而不是一个字符串。

        【讨论】:

          【解决方案4】:

          为了排序后的 ObservableCollection 反映源集合中的所有更改,您可以使用我的 ObservableComputations 库。使用这个库你可以像这样编写代码:

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

          sortedGraphicObjects 是 ObservableCollection,反映了 GraphicObjects 集合和 Nom 属性的所有变化。确保 Nom 属性通过INotifyPropertyChanged 接口通知更改。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-07-25
            • 2013-01-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-06
            • 1970-01-01
            相关资源
            最近更新 更多