两年前,曾经写过一篇文章:一种简单易用的WPF ListView点击列排序的方法,演示通过WPF中的CollectionView来对ListView进行排序,具体排序的执行是这样的:

在.NET 3.5+环境下,如果目标数据是IList,程序会使用Expression Tree来生成并设置ListCollectionView类型的CustomSort属性从而进行排序。

在.NET 3.0+环境下,会使用最原始CollectionView的SortDescriptions属性来排序。

 

但是上述排序方法不是很灵活,因此本文演示在WPF下使用LINQ来排序的方法,当然开发者不需要手动写LINQ排序代码,程序创建了一个叫LinqCollectionView的类型,通过它来把排序方式定义好就可以了,程序内部会使用LINQ来执行排序。当然LinqCollectionView仅用于排序,和WPF的ICollectionView接口没有任何继承关系,且目前不支持ObservableCollection<T>。

WPF的CollectionView诞生在.NET 3.0,而.NET 3.5后LINQ才出现,而Windows 8中WinRT的CollectionView就没有了SortDescriptions和GroupDescriptions属性,微软推荐开发者直接使用LINQ来操作数据。

 

下图:本文示例程序

WPF ListView设置ListViewItem数据源 wpf listview排序_WPF

 

比如我们的数据元素类型是这样一个简单的类:

publicclassItem

{

    public Item(string name, int score)

    {

        Name = name;

        Score = score;

    }

 

    publicstring Name { get; privateset; }

    publicint Score { get; privateset; }

 

    publicstaticItem[] GetData()

    {

        returnnewItem[]

        {

            newItem("Liu", 86),

            newItem("Zhang", 32),

            newItem("Li", 21),

            newItem("Wang", 100),

            newItem("Zhao", 78)

        };

    }

}

 

Name代表姓名,Score代表成绩。GetData方法用来生成测试数据。

排序规则这样定义:

姓名默认递增排序,且不区分大小写。

程序默认递减排序。

 

在XAML上,定义好ListView:

<ListView Name="listView">

    <ListView.ItemContainerStyle>

        <Style TargetType="ListViewItem">

            <Setter Property="HorizontalContentAlignment" Value="Stretch" />

        </Style>

    </ListView.ItemContainerStyle>

    <ListView.View>

        <GridView>

            <GridViewColumn DisplayMemberBinding="{Binding Name}" Header="姓名"/>

            <GridViewColumn Header="成绩">

                <GridViewColumn.CellTemplate>

                    <DataTemplate>

                        <ProgressBar Height="20" Value="{Binding Score,Mode=OneTime}" MinWidth="100"/>

                    </DataTemplate>

                </GridViewColumn.CellTemplate>

            </GridViewColumn>

        </GridView>

    </ListView.View>

</ListView>

 

然后需要加入执行代码:

var collectionView =newLinqCollectionView<Item>(

    Item.GetData(),

    newColumnSortData<Item>((x, y) =>StringComparer.OrdinalIgnoreCase.Compare(, )),

    newColumnSortData<Item>(i => i.Score, ColumnSortDirection.Descending));

 

LinqCollectionView<Item>.SetListView(listView, collectionView);

程序就OK了。

 

程序的主要类型就是LinqCollectionView<T>,T就是数据元素的类型,LinqCollectionView继承自MVVM Light中的ViewModelBase,因为需要提供集合的改变通知。注意这里集合改变通知不是指那个INotifyCollectionChanged接口,集合本身不会发生变化,LINQ排序后会生成一个新的IEnumerable<T>,所以这个新的属性会代替原来的集合属性。

 

该类型的构造函数是这样的:

public LinqCollectionView(IEnumerable<T> source, paramsColumnSortData<T>[] sortData)

 

source当然就是原始的集合。sortData就是具体排序的设置数据,我们来看ColumnSortData<T>这个类型。

WPF ListView设置ListViewItem数据源 wpf listview排序_数据_02

 

其中ColumnSortDirection枚举代表排序的方向:

publicenumColumnSortDirection

{

    Ascending,

    Descending

}

Ascending代表递增,Descending代表递减。

 

那么ColumnSortData<T>的InitialDirection属性代表着此项排序第一次进行时的排序方向,也就是当这一列的GridViewColumnHeader第一次被点击后,是进行递增还是递减的排序。

Status属性的类型是可为null的ColumnSortDirection类型,当为null时则代表当前列没有被排序,当然也可能是排序后用户又点击了其他列,那么本列顺序被打乱,Status属性也会是null。

 

最后两个属性是两种排序方式(只能二选一),KeySelector属性是通过一个Func<T, Object>委托,来抽取集合项目中的一个属性,然后对这个属性进行排序。类似WPF CollectionView中SortDescription中的属性名称(当然KeySelector是直接返回属性,SortDescription是通过反射获取属性,KeySelector拥有绝对性能优势)。

另一个种排序方式是通过Comparison<T>委托,这个委托不是我定义的,就在System命名空间里,.NET 2.0就有。这种方式类似ListCollectionView中的CustomSort属性中的IComparer类型,只不过直接通过一个委托,这样用户就不用再执行IComparer类型了。

 

因此ColumnSortData有两种构造方式:

public ColumnSortData(Func<T, object> selector, ColumnSortDirection direction =ColumnSortDirection.Ascending)

public ColumnSortData(Comparison<T> comparison, ColumnSortDirection direction =ColumnSortDirection.Ascending)

 

那么再看上面的LinqCollectionView的创建代码,这回加上注释,是这样的:

var collectionView =newLinqCollectionView<Item>(

    Item.GetData(),

    newColumnSortData<Item>((x, y) =>StringComparer.OrdinalIgnoreCase.Compare(, )),

    //使用Comparison<T>直接返回排序结果

    newColumnSortData<Item>(i => i.Score, ColumnSortDirection.Descending));

    //使用KeySelector来返回Score属性

 

 

当前版本的源代码下载      下载页面       注意:链接是微软SkyDrive页面,下载时请用浏览器直接下载,用某些下载工具可能无法下载       源代码环境:Microsoft Visual Studio Express 2012 for Windows Desktop      注意:源代码不包含引用的外部类库文件:MVVM Light

作者:Mgen