65.9K
CodeProject 正在变化。 阅读更多。
Home

使用IComparer对WPF ListView进行更通用的排序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.59/5 (14投票s)

2008年5月11日

Ms-PL

2分钟阅读

viewsIcon

90334

downloadIcon

1531

使用通用方法对 WPF ListView 进行排序的简单方法。

引言

默认情况下,没有简单的方法可以在 WPF 中对 ListView 进行排序。虽然 MSDN 上提供了关于如何对 ListView 进行排序的示例,但它不是很令人满意。该示例基于列的标题而不是实际的 DisplayMemberBinding 属性对 ListView 进行排序。这不是一个最佳解决方案,因为列标题不一定包含文本。其次,列标题可能与实际属性名称不同。此外,我认为这在多语言应用程序中也无法很好地工作。

背景

我想要一个更通用的解决方案来解决这个问题。在尝试了一段时间后,我最终得到了如下所示的解决方案。

要求

  • 该解决方案需要易于附加到 ListView,而无需每次添加大量代码。来自 WPF 的新的 附加属性功能(使用 Ramora)模式很好地解决了这个问题。
  • 排序需要可定制。通过使用 ListCollectionViewCustomSort 属性,可以轻松实现这一点。

使用代码

要创建自定义比较器,您需要实现抽象基类 ListViewCustomComparer<> 并创建您自己的比较器。在示例应用程序中,我创建了一个 PersonComparer

public class PersonComparer : ListViewCustomComparer<Person>
{

/// <summary>
/// Compares the specified x to y.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns></returns>
public override int Compare(Person x, Person y)
{
    try
    {
        String valueX = String.Empty, valueY = String.Empty;
        switch (SortBy)
        {
        default:
        case "FirstName":
            valueX = x.FirstName;
            valueY = y.FirstName;
        break;
        case "LastName":
            valueX = x.LastName;
            valueY = y.LastName;
        break;
        case "Age":
            if (SortDirection.Equals(ListSortDirection.Ascending))
                return x.Age.CompareTo(y.Age);
            else
                return (-1) * x.Age.CompareTo(y.Age);
        }
        if (SortDirection.Equals(ListSortDirection.Ascending))
            return String.Compare(valueX, valueY);
        else 
            return (-1) * String.Compare(valueX, valueY);
    }
    catch (Exception)
    {
        return 0;
    }
}

SortBy 值是在 MainWindow.xaml 标记代码中设置的 DisplayMemberBinding 的值。

MainWindow.xaml:

<GridViewColumn Header=“FirstName“ Width=“100“ DisplayMemberBinding=“{Binding FirstName}“ />
<GridViewColumn Header=“LastName“ Width=“100“ DisplayMemberBinding=“{Binding LastName}“ />
lt;GridViewColumn Header=“Age“ Width=“100“ DisplayMemberBinding=“{Binding Age}“ />

MainWindow 本身中,您需要添加本地 xml:ns 和数据模板,这些模板用于在排序的列上显示带有箭头的不同标题。您还需要将 ListViewSorter.CustomListViewSorter 属性添加到 ListView XML 元素。

<Window x:Class="WpfListViewSorting.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfListViewSorting"
    Title="WpfListViewSorting Demo" Height="300" Width="400">
    <Window.Resources>
    <DataTemplate x:Key="ListViewHeaderTemplateDescendingSorting">
        <DockPanel>
            <TextBlock Text="{Binding}"/>
        <Path x:Name="arrow"
            StrokeThickness = "1" 
            Fill = "gray"
            Data = "M 5,10 L 15,10 L 10,5 L 5,10"/>
    </DockPanel>
    </DataTemplate>
<DataTemplate x:Key="ListViewHeaderTemplateAscendingSorting">
<DockPanel>
    <TextBlock Text="{Binding }"/>
    <Path x:Name="arrow"
    StrokeThickness = "1" 
    Fill = "gray"
    Data = "M 5,5 L 10,10 L 15,5 L 5,5"/>
</DockPanel>
</DataTemplate>

<DataTemplate x:Key="ListViewHeaderTemplateNoSorting">
    <DockPanel>
        <TextBlock Text="{Binding }"/>
    </DockPanel>
</DataTemplate>

</Window.Resources>
<Grid>
    <ListView Margin="5" 
        VirtualizingStackPanel.IsVirtualizing="True"
        IsSynchronizedWithCurrentItem="True"
        local:ListViewSorter.CustomListViewSorter="WpfListViewSorting.PersonComparer"
        x:Name="lstView" >
    <ListView.View>
        <GridView AllowsColumnReorder="True">
            <GridViewColumn Header="FirstName" Width="100" 
                     DisplayMemberBinding="{Binding FirstName}" />
            <GridViewColumn Header="LastName" Width="100" 
                     DisplayMemberBinding="{Binding LastName}" />
            <GridViewColumn Header="Age" Width="100" 
                     DisplayMemberBinding="{Binding Age}" />
        </GridView>
    </ListView.View>
    </ListView >
</Grid>
</Window>

这是将排序添加到 ListView 所需添加的所有代码。对于下一个 ListView,您只需要将 local:ListViewSorter.CustomListViewSorter = "WpfListViewSorting.PersonComparer" 属性添加到它以激活它的工作(如果绑定对象相同;否则,创建一个新的比较器)。ListViewSorter 将在 Dictionary 中跟踪之前的排序方向和排序列,该 Dictionary 包含 ListViewSortItem 的集合。

关注点

暂无。 祝您编码愉快!

历史

  • 2008-05-24 - 修改了代码示例以检查 Visual Studio 设计模式,因此不会导致任何错误。
© . All rights reserved.