您的位置:首页 > 其它

WPF and Silverlight 学习笔记(二十五):使用CollectionView实现对绑定数据的排序、筛选、分组

2012-06-07 11:14 931 查看
在第二十三节,我们使用CollectionView实现了对于绑定数据的导航,除导航功能外,还可以通过CollectionView对数据进行类似于DataView的排序、筛选等功能。

一、数据的排序:

使用第二十四节的数据源,查询所有的产品信息:

1: <Window x:Class="WPF_24.CollectionViewSortData"

2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

4:     xmlns:lib="clr-namespace:WPF_24_Library;assembly=WPF_24_Library"

5:     Title="CollectionViewSortData" Height="300" Width="500">

6:     <Window.Resources>

7:         <ObjectDataProvider x:Key="myDataSource"

8:                             ObjectType="{x:Type lib:DataControl}"

9:                             MethodName="GetAllProductInfo" />

10:     </Window.Resources>

11:     <Grid Margin="5">

12:         <Grid.RowDefinitions>

13:             <RowDefinition />

14:             <RowDefinition Height="50" />

15:         </Grid.RowDefinitions>

16:         <ListBox Grid.Row="0"

17:                  DataContext="{StaticResource myDataSource}"

18:                  ItemsSource="{Binding}">

19:             <ListBox.ItemTemplate>

20:                 <DataTemplate>

21:                     <WrapPanel>

22:                         <TextBlock Text="{Binding Path=ProductID}" Width="50" />

23:                         <TextBlock Text="{Binding Path=ProductName}" Width="300" />

24:                         <TextBlock Text="{Binding Path=UnitPrice}" Width="50" />

25:                     </WrapPanel>

26:                 </DataTemplate>

27:             </ListBox.ItemTemplate>

28:         </ListBox>

29:         <WrapPanel Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">

30:             <TextBlock Text="第一排序:" VerticalAlignment="Center" />

31:             <ComboBox SelectedIndex="0" Width="80" x:Name="cmbColumnA">

32:                 <ComboBox.Items>

33:                     <ComboBoxItem Tag="ProductID">产品编号</ComboBoxItem>

34:                     <ComboBoxItem Tag="ProductName">产品名称</ComboBoxItem>

35:                     <ComboBoxItem Tag="UnitPrice">产品单价</ComboBoxItem>

36:                 </ComboBox.Items>

37:             </ComboBox>

38:             <TextBlock Text="第二排序:" VerticalAlignment="Center" />

39:             <ComboBox SelectedIndex="0" Width="80" x:Name="cmbColumnB">

40:                 <ComboBox.Items>

41:                     <ComboBoxItem Tag="ProductID">产品编号</ComboBoxItem>

42:                     <ComboBoxItem Tag="ProductName">产品名称</ComboBoxItem>

43:                     <ComboBoxItem Tag="UnitPrice">产品单价</ComboBoxItem>

44:                 </ComboBox.Items>

45:             </ComboBox>

46:             <Button Content="排序" Margin="10,0,0,0" Click="Button_Click" />

47:         </WrapPanel>

48:     </Grid>

49: </Window>


实现对数据的排序,使用的是CollectionView对象中的SortDescriptions集合属性,其包含多个SortDescription对象,按照其先后顺序对数据实现排序。注意SortDescription对象的构造方法的两个参数,第一个参数是字符串类型的,表示数据类型中的某个属性的属性名,其属性的类型必须实现IComparable接口,即实现相应的排序规则;第二参数是ListSortDeirection枚举,表示排序的顺序是正序还遇倒序。

本例应在按钮的Click事件中定义如下的代码:

1: private void Button_Click(object sender, RoutedEventArgs e)

2: {

3:     // 获取数据源适配器

4:     ObjectDataProvider provider =

5:         (ObjectDataProvider) (this.FindResource("myDataSource"));

6:     // 获取数据源

7:     List<ProductInfo> collections = (List<ProductInfo>) (provider.Data);

8:

9:     // 获取数据源对应的CollectionView

10:     ICollectionView view = CollectionViewSource.GetDefaultView(collections);

11:     // 清除原有的排序

12:     view.SortDescriptions.Clear();

13:

14:     // 获取要排序的两个列的列名

15:     string firstColumn = ((ComboBoxItem) (cmbColumnA.SelectedItem)).Tag.ToString();

16:     string secendColumn = ((ComboBoxItem)(cmbColumnB.SelectedItem)).Tag.ToString();

17:

18:     if (view.CanSort)

19:     {

20:         // 添加排序规则(注意添加的顺序)

21:         view.SortDescriptions.Add(

22:             new SortDescription(firstColumn,ListSortDirection.Ascending));

23:         view.SortDescriptions.Add(

24:             new SortDescription(secendColumn, ListSortDirection.Ascending));

25:     }

26: }


应用程序执行这后的效果如图:



二、实现对数据的筛选

实现对数据的筛选使用的是CollectionView对象的Filter属性,Filter属性的类型是Predicate<object>委托,其要求绑定的方法返回一个布尔值,系统将依据其返回的布尔值筛选数据,使得筛选后的所有数据满足使方法返回True。例如,在前面的例子中添加对单价的筛选条件:

1: <!-- 在界面中添加Grid的一行,并在此行中添加筛选数据所需的界面元素,省略其他代码 -->

2: <WrapPanel Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center">

3:     <TextBlock Text="产品单价范围:" />

4:     <TextBox Width="50" x:Name="lowPrice" />

5:     <TextBlock Text="~" />

6:     <TextBox Width="50" x:Name="highPrice" />

7:     <Button Content="筛选" Margin="10,0,0,0" Click="Button_Click_1" />

8: </WrapPanel>


在按钮的Click事件中定义如下代码:

1: private void Button_Click_1(object sender, RoutedEventArgs e)

2: {

3:     // 获取数据源适配器

4:     ObjectDataProvider provider =

5:         (ObjectDataProvider)(this.FindResource("myDataSource"));

6:     // 获取数据源

7:     List<ProductInfo> collections = (List<ProductInfo>)(provider.Data);

8:

9:     // 获取数据源对应的CollectionView

10:     ICollectionView view = CollectionViewSource.GetDefaultView(collections);

11:

12:     if (view.CanFilter)

13:   {

14:         // 绑定数据筛选的条件

15:         view.Filter = new Predicate<object>(dataFilter);

16:     }

17: }

18:

19: // 数据筛选的条件

20: private bool dataFilter(object obj)

21: {

22:     decimal low = decimal.Parse(lowPrice.Text);

23:     decimal high = decimal.Parse(highPrice.Text);

24:

25:     ProductInfo info = (ProductInfo) obj;

26:

27:     return info.UnitPrice >= low && info.UnitPrice <= high;

28: }


执行的结果如图所示,从中也可以看出,筛选可以和排序一起使用



三、实现数据分组

实现数据分组,使用的是CollectionView的GroupDescriptions集合属性,其包含的元素是GroupDescription抽象类对象,在Framework中,系统定义了一个GroupDescription的子类PropertyGroupDescription,实现根据数据的某属性进行分组的功能。



例如,实现对于产品单价的分组:

在XAML的Grid中添加一行,添加对于分组的显示:

1: <!-- 实现分组的操作,省略其他代码 -->

2: <WrapPanel Grid.Row="3" VerticalAlignment="Center" HorizontalAlignment="Center">

3:     <TextBlock Text="分组条件:" />

4:     <RadioButton Content="按单价分组" IsChecked="True" Checked="GroupByUnitPrice_Checked" />

5:     <RadioButton Content="按名称分组" Checked="GroupByProductName_Checked" />

6: </WrapPanel>


在后台CS文件中,实现GroupByUnitPrice_Checked方法,实现根据UnitPrice分组:

1: private void GroupByUnitPrice_Checked(object sender, RoutedEventArgs e)

2: {

3:     // 获取数据源适配器

4:     ObjectDataProvider provider =

5:         (ObjectDataProvider)(this.FindResource("myDataSource"));

6:     // 获取数据源

7:     List<ProductInfo> collections = (List<ProductInfo>)(provider.Data);

8:

9:     // 获取数据源对应的CollectionView

10:     ICollectionView view = CollectionViewSource.GetDefaultView(collections);

11:

12:     if (view.CanGroup)

13:   {

14:         view.GroupDescriptions.Clear();

15:         view.GroupDescriptions.Add(

16:             new PropertyGroupDescription("UnitPrice"));

17:   }

18: }


执行的结果如下:



定义分组样式:
可以添加ListBox的GroupStyle,以显示分组的样式:

例如:使用默认的分组样式:

1: <ListBox ... >

2:     <!-- ... -->

3:     <ListBox .GroupStyle>

4:         <x:Static Member="GroupStyle.Default" />

5:     </ListBox.GroupStyle>

6: </ListBox>


执行的结果如下:



还可以自定义分组样式,例如:

1: <ListBox.GroupStyle>

2:     <!--<x:Static Member="GroupStyle.Default" />-->

3:     <GroupStyle>

4:         <GroupStyle.HeaderTemplate>

5:             <DataTemplate>

6:                 <TextBlock Background="#DDD" Foreground="#333" FontWeight="Bold">

7:                     <TextBlock Text="{Binding Path=Name}" />

8:                   (<TextBlock Text="{Binding Path=ItemCount}" />)

9:                 </TextBlock>

10:             </DataTemplate>

11:       </GroupStyle.HeaderTemplate>

12:     </GroupStyle>

13: </ListBox.GroupStyle>


执行结果如下:



自定义分组条件:
可以通过定义值转换器的方式自定义分组的条件。例如,按产品名称分组时,按照产品名称的第一个字母进行分组,而不是按照完整的名称分组。

定义ProductNameGroupConverter类,实现IValueConverter接口:

1: using System;

2: using System.Globalization;

3: using System.Windows.Data;

4:

5: namespace WPF_24

6: {

7:     public class ProductNameGroupConverter : IValueConverter

8:   {

9:         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

10:         {

11:           //将包含产品名称的Object对象value转换为字符串

12:             string val = (string)value;

13:

14:             return val.Substring(0, 1) + "...";

15:         }

16:

17:       public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

18:       {

19:             throw new NotImplementedException();

20:         }

21:     }

22: }


在GroupByProductName_Checked方法中:

1: private void GroupByProductName_Checked(object sender, RoutedEventArgs e)

2: {

3:     // 获取数据源适配器

4:     ObjectDataProvider provider =

5:         (ObjectDataProvider)(this.FindResource("myDataSource"));

6:     // 获取数据源

7:     List<ProductInfo> collections = (List<ProductInfo>)(provider.Data);

8:

9:     // 获取数据源对应的CollectionView

10:     ICollectionView view = CollectionViewSource.GetDefaultView(collections);

11:

12:     if (view.CanGroup)

13:   {

14:         view.GroupDescriptions.Clear();

15:         view.GroupDescriptions.Add(

16:           new PropertyGroupDescription(

17:               "ProductName",

18:               new ProductNameGroupConverter()));

19:     }

20: }


执行结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐