数据视图

数据视图是在后台工作的,用于协调绑定数据的集合。使用数据视图可以添加导航逻辑、实现数据过滤、排序、分组。

当将集合或者DataTable绑定到ItemsControl控件时,会不加通告地在后台创建数据视图(位于数据源和绑定的控件之间)。数据视图是进入数据源的窗口,可以跟踪当前项,并且支持各种功能(排序、过滤、分组等)。这些功能和数据对象本身是相互独立的,这意味着可以在窗口的不同部分使用不同的方式绑定相同的数据源。例如:可将同一产品集合绑定到两个不同的列表,并对产品进行过滤显示不同的记录。

View对象

使用的视图对象取决于数据对象的类型。所有视图都继承自CollectionView类,比较特殊的两个实现是:ListCollectionView和BindingListCollectionView。

  • 如果数据源实现了IBindingList接口,就会创建BindingListCollectionView视图(DataTable对象绑定时)
  • 如果数据源没有实现IBindingList接口,但实现了IList接口,就会创建ListCollectionView视图,当绑定ObservableCollection集合时
  • 如果数据源没有实现IBindingList或IList接口,但是实现了IEnumerable接口时,就会得到基本的CollectionView视图

检索视图对象

得到当前视图对象的方法

ICollectionView view = CollectionViewSource.GetDefaultView(lstProducts.ItemsSource);

根据需要转换成合适的类即可。

视图导航

  • 可使用视图对象进行下列操作:
  • 获取列表中的项数(Count属性)
  • 获取当前数据对象的引用(CurrentItem属性)
  • 当前位置索引(CurrentIndex属性)
  • 从一条记录移动到另一条(MoveCurrentToFirst,MoveCurrentToLast,MoveCurrentToNext,MoveCurrentToPrevious,MoveCurrentTo,MoveCurrentToPosition)

以声明方式创建视图

可以在代码中检索视图或者修改视图,还可以在XAML标记中创建CollectionViewSource对象,然后将其绑定到控件上。

CollectionViewSource的两个重要属性就是View和Source,View属性封装了视图的对象,Source属性封装了数据源。还有SortDescriptions和GroupDescriptions

<Window.Resources>
  <local:PriceRangeProductGrouper x:Key="Price50Grouper" GroupInterval="50"/>
  <CollectionViewSource x:Key="GroupByRangeView">
    <CollectionViewSource.SortDescriptions>
      <component:SortDescription PropertyName="UnitCost" Direction="Ascending"/>        
    </CollectionViewSource.SortDescriptions>
    <CollectionViewSource.GroupDescriptions>
      <PropertyGroupDescription PropertyName="UnitCost" Converter="{StaticResource Price50Grouper}"/>
    </CollectionViewSource.GroupDescriptions>
  </CollectionViewSource>
</Window.Resources>

代码中的实现:

CollectionViewSource viewSource = (CollectionViewSource)this.FindResource("GroupByRangeView");
viewSource.Source = products;

过滤、排序、分组

过滤集合

通过过滤可以显示符合特定条件的子集。可使用视图对象的Filter属性设置过滤器。

ListCollectionView view = CollectionViewSource.GetDefaultView(lstProducts.ItemsSource) as ListCollectionView;
if (view != null)
{
    filterer = new ProductByPriceFilterer(minimumPrice);
    view.Filter = new Predicate<object>(filterer.FilterItem);
    view.Refresh();
}
public class ProductByPriceFilterer
{
    public decimal MinimumPrice
    {
        get;
        set;
    }
    public ProductByPriceFilterer(decimal minimumPrice)
    {
        MinimumPrice = minimumPrice;
    }
    public bool FilterItem(Object item)
    {
        Product product = item as Product;
        if (product != null)
        {
            if (product.UnitCost > MinimumPrice)
            {
                return true;
            }
        }
        return false;
    }
}

过滤DataTable对象

通过BindingListCollectionView的CustomFilter 属性

decimal minimumPrice;
if (Decimal.TryParse(txtMinPrice.Text, out minimumPrice))
{
    BindingListCollectionView view = CollectionViewSource.GetDefaultView(lstProducts.ItemsSource) as BindingListCollectionView;
    if (view != null)
    {
        view.CustomFilter = "UnitCost > " + minimumPrice.ToString();
    }
}

排序

使用视图进行排序,最简单的办法就是根据每个数据项中的一个或者多个属性的值进行排序。使用SortDescriptions对象来确定希望排序的字段。包含了希望排序的字段和排序方向(升序或者降序),按照希望排序的先后进行添加即可。

ICollectionView view = CollectionViewSource.GetDefaultView(lstProducts.ItemsSource);
view.SortDescriptions.Add(new SortDescription("ModelName", ListSortDirection.Ascending));

还可以自定义排序,只能用于ListCollectionView视图(不能用于BindingListCollectionView)。ListCollectionView提供了CustomSort属性来接收一个IComparer对象,这个对象在两个数据项之间进行比较,并且指示较大项。

public class SortByModelNameLength : System.Collections.IComparer
{
    public int Compare(object x, object y)
    {
        Product productX = (Product)x;
        Product productY = (Product)y;
        return productX.ModelName.Length.CompareTo(productY.ModelName.Length);
    }
}
ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(lstProducts.ItemsSource);
view.CustomSort = new SortByModelNameLength();

分组

简单方式分组(根据单个属性),复杂方式分组(自定义回调函数)

通过视图的GroupDescriptions属性,添加分组依据。

ICollectionView view = CollectionViewSource.GetDefaultView(lstProducts.It
view.SortDescriptions.Add(new SortDescription("CategoryName", ListSortDir
view.SortDescriptions.Add(new SortDescription("ModelName", ListSortDirect
view.GroupDescriptions.Add(new PropertyGroupDescription("CategoryName"));

当时用分组后,列表为每个分组创建了单独的GroupItem对象,并且为列表添加了这些GroupItem对象。GroupItem是内容控件,所以每个GroupItem对象都包含一个适当的具有实际数据的容器(如ListBoxItem对象),显示分组的秘密是格式化GroupItem对象,使其突出显示。

可以使用样式来为列表中的所有GroupItem对象应用格式。可以通过ItemsControl的GroupStyle属性来实现,GroupStyle类包含了如下属性:

名称 说明
ContainerStyle 设置被应用到每个分组生成的GroupItem的样式
ContainerStyleSelector 通过代码来设置每个分组的GroupItem的正确样式
HeaderTemplate 允许用户为每个分组的头显示内容并创建模板
headerTemplateSelector 通过代码来为每个分组的头设置并创建模板
Panel 改变用于分组的模板,比如使用WrapPanel代替StackPanel,创建从左到右然后向下平铺分组的列表
<ListBox Grid.Row="1" Margin="7,3,7,10" Name="lstProducts" DisplayMemberPath="ModelName">
  <ListBox.GroupStyle>
    <GroupStyle>
      <GroupStyle.HeaderTemplate>
        <DataTemplate>                
            <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" 
  Foreground="White" Background="LightGreen" Margin="0,5,0,0" Padding="3"/>
          </DataTemplate>
      </GroupStyle.HeaderTemplate>
    </GroupStyle>
  </ListBox.GroupStyle>
</ListBox>
  • 范围分组

需要提供一个转换器,检查数据源中的一个字段或者多个字段,并返回组标题。只需要多个数据对象使用相同的组标题,就可以被放到相同的分组中。

  • 分组和虚拟化

为了降低控件的内存开销,绑定较长的列表时能够提升速度,需要使用控件支持虚拟化。通过VirtualizingStackPanel.IsVirtualizingWhenGrouping=true来讲分组列表和未分组列表获取相同的虚拟化性能提升效果。

实时成型

如果改变正在使用的视图的过滤、排序、分组,就需要调用ICollectionViewSource.Refresh()方法来刷新视图,并确保正确的项出现在列表中。

实时成型的功能:监视特定属性中的变化,如果发生变化,就确定响应更改会影响当前视图并触发刷新动作。

使用实时成型需要满足的3个标准:

  • 数据对象必须实现INotifyPropertyChanged,当属性变化时,使用该接口发出通知
  • 集合必须实现ICollectionViewLiveShaping,标准的ListCollectionView和BindingListCollectionView都实现了这个接口
  • 必须明确启用实时成型

实时成型会增加额外的开销,因此需要设置3个独立的属性:IsLiveFiltering、IsLiveSorting、IsLiveGrouping。通过这3个属性来设置哪些动作启用实时成型,除此之外,还需要设置哪些属性的变化会触发实时成型。

ListCollectionView lcview = CollectionViewSource.GetDefaultView(lstProducts.ItemsSource) as ListCollectionView;// Now if you edit and reduce the price (below the filter condition) the record will disappear automatically.lcview.IsLiveFiltering = true;lcview.LiveFilteringProperties.Add("UnitCost");

WPF进阶技巧和实战03-控件(5-列表、树、网格03)的更多相关文章

  1. WPF进阶技巧和实战03-控件(3-文本控件及列表控件)

    系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...

  2. WPF进阶技巧和实战03-控件(4-基于范围的控件及日期控件)

    系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...

  3. WPF进阶技巧和实战06-控件模板

    逻辑树和可视化树 System.Windows.LogicalTreeHelper System.Windows.Media.VisualTreeHelper 逻辑树类(LogicalTreeHelp ...

  4. WPF进阶技巧和实战07--自定义元素02

    在01节中,研究了如何开发自定义控件,下节开始考虑更特殊的选择:派生自定义面板以及构建自定义绘图 创建自定义面板 创建自定义面板是一种比较常见的自定义控件开发子集,面板可以驻留一个或多个子元素,并且实 ...

  5. WPF进阶技巧和实战09-事件(2-多点触控)

    多点触控输入 多点触控输入和传统的基于比的输入的区别是多点触控识别手势,用户可以移动多根手指以执行常见的操作,放大,旋转,拖动等. 多点触控的输入层次 WPF允许使用键盘和鼠标的高层次输入(例如单击和 ...

  6. WPF进阶技巧和实战03-控件(1-控件及内容控件)

    所有控件都继承自System.Windows.Controls.Control类,这个类添加一些基本结构: 设置控件内容对齐方式 (HorizontalContentAlignment,Vertica ...

  7. WPF进阶技巧和实战03-控件(5-列表、树、网格02)

    数据模板 样式提供了基本的格式化能力,但是不管如何修改ListBoxItem,他都不能够展示功能更强大的元素组合,因为了每个ListBoxItem只支持单个绑定字段(通过DisplayMemberPa ...

  8. WPF进阶技巧和实战03-控件(5-列表、树、网格01)

    列表控件 ItemsControl为列表项控件定义了基本功能,下图是ItemsControl的继承关系: 在继承自ItemsControl类的层次结构中,还显示了项封装器(MenuItem.TreeV ...

  9. WPF进阶技巧和实战08-依赖属性与绑定03

    数据提供者 在大多数的代码中,都是通过设置元素的DataContext属性或者列表控件的ItemsSource属性,从而提供顶级的数据源.当数据对象是通过另一个类构造时,可以有其他选择. 一种是作为窗 ...

随机推荐

  1. Spring详解(八)------常用的连接池配置

    首先,我们准备Jdbc属性文件 jdbc.properties,用于保存连接数据库的信息,利于我们在配置文件中的使用 jdbc.driver=com.mysql.jdbc.Driver jdbc.ur ...

  2. ArcGIS Engine中实现ArcMap的捕捉效果

    注意要将捕捉相关接口的对象放在OnCreate方法中,这样在初始化就可以有捕捉效果,(捕捉对象赋值放在OnClick中出现第一次点击之前不能捕捉的BUG) 这里是直接在工具中实现的 ,可以按需求将捕捉 ...

  3. Javascript - Vue - 动画

    动画状态类名 vue动画通过将需要执行动画的标签放入transition标签中,再通过设置预置的vue动画类名的css样式来控制动画的呈现效果. 开场动画状态的三个类名 v-enter:动画开始之前的 ...

  4. apche的BeanUtils避免使用!

    原文出处 建议,不要使用apache的BeanUtils进行属性拷贝了,建议使用Spring 核心包bean下面的BeanUtils进行替代! 使用和对比出处

  5. linux 常用命令(四)——(centos7-centos6.8)Vim安装

    centos是默认安装了vi编辑器的,vim编辑器是没安装或者未完全安装的,个人习惯用vim,所以记录一下vim编辑器的安装: 1.查看vim相关软件信息: yum search vim 2.在线安装 ...

  6. linux备份恢复命令

    dump 发行版不自带,需要 yum 或 apt 安装.安装时 restore 也会自动安装. 支持分区和增量备份(仅支持分区增量,目录备份不支持增量).(第一次完全备份,第二次及以后只备份增加和修改 ...

  7. [题解] P4556 [Vani有约会]雨天的尾巴

    [题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...

  8. LVS实现(VS/DR)负载均衡和Keepalived高可用

    LVS是Linux Virtual Server的简写即Linux虚拟服务器,是一个虚拟的服务器集群系统一组服务器通过高速的局域网或者地理分布的广域网相互连接,在它们的前端有一个负载调度器(Load ...

  9. Java基础之SPI机制

    SPI 机制,全称为 Service Provider Interface,是一种服务发现机制.它通过在 ClassPath 路径下的 META-INF/services 文件夹查找文件,自动加载文件 ...

  10. (八)羽夏看C语言——C番外篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...