zoukankan      html  css  js  c++  java
  • [转]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

  • 相关阅读:
    我的知识库(4) java获取页面编码(Z)
    知识库(3)JAVA 正则表达式 (超详细)
    The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the associated filter. Struts
    某人总结的《英语听力的技巧 》,挺搞的
    我的知识库(5)java单例模式详解
    构建可扩展程序
    SerialPort (RS232 Serial COM Port) in C# .NET
    Python学习笔记——String、Sequences
    UI题目我的答案
    jQuery学习系列学会操纵Form表单元素(1)
  • 原文地址:https://www.cnblogs.com/luohengstudy/p/3549511.html
Copyright © 2011-2022 走看看