WPF - 在按多列排序时使用自定义比较器

6
我有一个ListView(GridView),我想按照两个列排序,所以如果两个或更多的项目在第一列中具有相同的值,则按第二列排序。非常简单。但是当按A-Z排序时,空字符串出现在顶部。我希望将它们移动到底部。我编写了一个比较器(IComparer)来处理这个问题,但我不确定如何使用它。
以下是我尝试过的代码:
 Dim view As ListCollectionView = CollectionViewSource.GetDefaultView(myCollection)
 Using view.DeferRefresh
    view.SortDescriptions.Clear()
    view.SortDescriptions.Add(New SortDescription(sortHeader.Header, direction))
    view.SortDescriptions.Add(New SortDescription(otherColumn, direction))
    view.CustomSort = New MyComparer()
 End Using

问题在于我的比较器得到的是我的类的类型,而不是被排序的属性/列的值。因此,如果这个类是Foo,我正在按Foo.Bar排序,我会得到整个Foo类,而不仅仅是Bar的值(这实际上是它应该关心的,因为这就是它所排序的)。
我的比较器如何知道要比较哪个属性?也许我在这里做错了什么,因为这毫无意义。我希望得到一个String(属性类型)来比较x和y...
有人知道怎么做吗?
1个回答

7

您的IComparer实现将获得整个对象,您需要找出被点击的列,可能需要进行以下操作:

this.AddHandler(GridViewColumnHeader.ClickEvent, 
                new RoutedEventHandler(Column_Sort));

然后将其输入到您的MyComparer中,可能需要修改构造函数以接受属性路径。

Column_Sort中,您可以像这样获取属性路径(我对vb有点生疏,但c#可以这样做:

void Column_Sort(object sender, RoutedEventArgs e)
{
  var memberBinding= ((GridViewColumnHeader)e.OriginalSource).Column.DisplayMemberBinding;
  var path = ((Binding)memberBinding).Path.Path;
}

然后将其输入到您的排序逻辑中。
Dim view As ListCollectionView = CollectionViewSource.GetDefaultView(myCollection)
 Using view.DeferRefresh
    view.SortDescriptions.Clear()
    view.SortDescriptions.Add(New SortDescription(sortHeader.Header, direction))
    view.SortDescriptions.Add(New SortDescription(otherColumn, direction))
    view.CustomSort = New MyComparer(PropertyPath)
 End Using

编辑: 您只需要自定义IComparer以支持多列排序,我在谷歌上搜索并找到了这个比较器实现,您可以将多个属性路径用逗号分隔并加上ASC/DESC后缀来传递给它,就像这样:

User.LastName DESC, User.FirstName DESC

我认为在UI方面,多列排序的惯例是需要按住 Ctrl 按钮。因此,您需要对 ListView 类进行子类化,并连接到 GridViewColumnHeader clicked 事件和 KeyDown 事件,以了解连续点击了哪些列,然后使用 IComparer 实现将其馈入。


这个方法在按一列排序时是有效的,但由于PropertyPath引用了被点击的列(也就是我的代码中的sortHeader),所以即使应该比较第二列(第二个SortDescription),它仍然会查找那一列。那么比较器如何知道它应该查找第一列(被点击的那一列)还是第二列(当有两个或更多列在第一列具有相同值时)? - grant
我在上面进行了一些更改,以尝试回答您确切的问题 :) - Jose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接