WPF进阶技巧和实战03-控件(5-列表、树、网格03)
数据视图
数据视图是在后台工作的,用于协调绑定数据的集合。使用数据视图可以添加导航逻辑、实现数据过滤、排序、分组。
当将集合或者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)的更多相关文章
- WPF进阶技巧和实战03-控件(3-文本控件及列表控件)
系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...
- WPF进阶技巧和实战03-控件(4-基于范围的控件及日期控件)
系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...
- WPF进阶技巧和实战06-控件模板
逻辑树和可视化树 System.Windows.LogicalTreeHelper System.Windows.Media.VisualTreeHelper 逻辑树类(LogicalTreeHelp ...
- WPF进阶技巧和实战07--自定义元素02
在01节中,研究了如何开发自定义控件,下节开始考虑更特殊的选择:派生自定义面板以及构建自定义绘图 创建自定义面板 创建自定义面板是一种比较常见的自定义控件开发子集,面板可以驻留一个或多个子元素,并且实 ...
- WPF进阶技巧和实战09-事件(2-多点触控)
多点触控输入 多点触控输入和传统的基于比的输入的区别是多点触控识别手势,用户可以移动多根手指以执行常见的操作,放大,旋转,拖动等. 多点触控的输入层次 WPF允许使用键盘和鼠标的高层次输入(例如单击和 ...
- WPF进阶技巧和实战03-控件(1-控件及内容控件)
所有控件都继承自System.Windows.Controls.Control类,这个类添加一些基本结构: 设置控件内容对齐方式 (HorizontalContentAlignment,Vertica ...
- WPF进阶技巧和实战03-控件(5-列表、树、网格02)
数据模板 样式提供了基本的格式化能力,但是不管如何修改ListBoxItem,他都不能够展示功能更强大的元素组合,因为了每个ListBoxItem只支持单个绑定字段(通过DisplayMemberPa ...
- WPF进阶技巧和实战03-控件(5-列表、树、网格01)
列表控件 ItemsControl为列表项控件定义了基本功能,下图是ItemsControl的继承关系: 在继承自ItemsControl类的层次结构中,还显示了项封装器(MenuItem.TreeV ...
- WPF进阶技巧和实战08-依赖属性与绑定03
数据提供者 在大多数的代码中,都是通过设置元素的DataContext属性或者列表控件的ItemsSource属性,从而提供顶级的数据源.当数据对象是通过另一个类构造时,可以有其他选择. 一种是作为窗 ...
随机推荐
- [转]C# 互操作性入门系列(三):平台调用中的数据封送处理
参考网址:https://www.cnblogs.com/FongLuo/p/4512738.html C#互操作系列文章: C# 互操作性入门系列(一):C#中互操作性介绍 C# 互操作性入门系列( ...
- AAC简介
AAC共有9种规格,以适应不同的场合的需要: MPEG-2 AAC LC 低复杂度规格(Low Complexity)--比较简单,没有增益控制,但提高了编码效率,在中等码率的编码效率以及音质方面,都 ...
- java基本数据类型和包装类之间的转换(装箱,拆箱)
1.装箱:把基本数据类型转换成包装类 1.1自动装箱 int t1=2; Integer t2 =t1; 1.2手动装箱 Integer t3 = new Integer(t1); 2.拆箱:把包装类 ...
- Python创建二维列表的正确姿势
Python创建二维列表的正确姿势 简介 Python中没有数组,使用list结构代替,并且list结构的功能更加强大: 支持动态扩容,无需担心元素过量 对list内的元素类型不做一致性约束 提供丰富 ...
- Shell脚本逐行读取文本内容并拆分,根据条件筛选文件
时间:2018-11-13 整理:byzqy 需求: 最近帮朋友写了一段脚本,他的需求是根据一份产品清单,去服务器上捞取对应产品编号的测试Log,数量大概有9000~10000条左右.文本内容大致如下 ...
- roslaunch 启动时修改参数
启动命令: roslaunch beginner_tutorials turtlemimic.launch arg1:=3.0 查询命令: rosparam get /param1 可以看到param ...
- 每天迁移MySQL历史数据到历史库Python脚本
#!/usr/bin/env python # coding:utf-8 #__author__ = 'Logan' import MySQLdb import sys import dat ...
- linux centos7 read 命令
2021-08-24 1. 命令简介 read 命令就是读取控制台输入,会将从键盘输入的数据分割成一个个字段依次存储在 parameter[0] .parameter[1] ......,若是没有指定 ...
- centos7 wget安装Tomcat7
2021-07-15 1.环境介绍 操作系统:centos7 jdk版本:jdk1.8.0.211 tomcat版本:tomcat7.0.109 2. 检查系统中是否已经安装 jdk ,如未安装, 请 ...
- 查看所有日志命令:journalctl
journalctl命令作用:实时查看所有日志(内核日志和应用日志) 语法格式: journalctl [参数] 常用参数:-k 查看内核日志-b 查看系统本次启动的日志-u 查看指定服务的日志-n ...