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






4.59/5 (14投票s)
使用通用方法对 WPF ListView 进行排序的简单方法。
引言
默认情况下,没有简单的方法可以在 WPF 中对 ListView
进行排序。虽然 MSDN 上提供了关于如何对 ListView
进行排序的示例,但它不是很令人满意。该示例基于列的标题而不是实际的 DisplayMemberBinding
属性对 ListView
进行排序。这不是一个最佳解决方案,因为列标题不一定包含文本。其次,列标题可能与实际属性名称不同。此外,我认为这在多语言应用程序中也无法很好地工作。
背景
我想要一个更通用的解决方案来解决这个问题。在尝试了一段时间后,我最终得到了如下所示的解决方案。
要求
- 该解决方案需要易于附加到
ListView
,而无需每次添加大量代码。来自 WPF 的新的 附加属性功能(使用 Ramora)模式很好地解决了这个问题。 - 排序需要可定制。通过使用
ListCollectionView
的CustomSort
属性,可以轻松实现这一点。
使用代码
要创建自定义比较器,您需要实现抽象基类 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 设计模式,因此不会导致任何错误。