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


    在第二十三节,我们使用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: }

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

    25-1

    二、实现对数据的筛选

    实现对数据的筛选使用的是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: }

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

    25-2

    三、实现数据分组

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

    25-4

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

    在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: }

    执行的结果如下:

    25-5

    定义分组样式:

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

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

       1: <ListBox ... >
       2:     <!-- ... -->
       3:     <ListBox .GroupStyle>
       4:         <x:Static Member="GroupStyle.Default" />
       5:     </ListBox.GroupStyle>
       6: </ListBox>

    执行的结果如下:

    25-6

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

       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>

    执行结果如下:

    25-7

    自定义分组条件:

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

    定义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: }

    执行结果如下:

    25-8

    文章来源:http://www.cnblogs.com/DragonInSea/archive/2009/06/08/1498617.html

  • 相关阅读:
    ConvertUtils的理解
    mysql存储过程 详细注释
    线程方法
    集合的方法
    StringStringBufferStringBuilder
    Java基础知识点1
    Java基础知识点
    索引+sql优化
    Oracle数据库02
    Oracle数据库01
  • 原文地址:https://www.cnblogs.com/luohengstudy/p/3549511.html
Copyright © 2020-2023  润新知