博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据视图
阅读量:6757 次
发布时间:2019-06-26

本文共 21566 字,大约阅读时间需要 71 分钟。

原文:

1、数据视图。

使用数据视图,可添加导航逻辑并实现过滤、排序和分组。

2、View对象。

当将结合(或DataTable)绑定到ItemsControl控件时,会不加通告地在后台创建数据视图---位于数据源和绑定的控件之间。数据视图是进入数据源的窗口,可以跟踪当前项,并且支持各种功能,如排序、过滤以及分组。使用的视图对象取决于数据对象的类型。所有视图都继承自CollectionView类,并且有两个继承自CollectionView类的特殊实现:ListCollectionView和BindingListCollectionView。下面是CollectionView类的工作原理:

a)、如果数据源实现了IBindList接口,就会创建BindingListCollectionView视图。当绑定到ADO.Net中的DataTable对象时会创建该视图。

b)、如果数据源没有实现IBindList接口,但实现了IList接口,就会创建ListCollectionView视图。当绑定到ObservableCollection集合(如产品列表)时,就会创建该视图。

c)、如果数据视图没有实现IBindingList或IList接口,但实现了IEnumerable接口,就会得到基本的CollectionView视图。

3、检索视图对象。

为得到当前使用的视图对象,可使用System.Windows.Data.CollectionViewSource类的GetDefaultView()静态方法。当调用GetDefaultView()方法时,传入数据源---正在使用的集合或DataTable对象。

如:ListCollectionView listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);

4、视图导航。

常用属性和常用方法:

Count:得到列表中的项数。

CurrentPosition:视图中的序号位置。

MoveCurrentToFirst():移动到第一条记录上。

MoveCurrentToLast():移动到最后一条记录上。

MoveCurrentToNext():移动到下一条记录上。

MoveCurrentToPrevious():移动到上一条记录。

MoveCurrentToPosition():移动到当前位置。

xml代码:

产品编号:
产品名字:
产品价格:
产品描述:
产品图片:
View Code

后台代码:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    //声明一个视图。    private ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.mainGrid.DataContext = productBll.GetCollectionProduct();        //通过GetDefaultView()方法获取数据视图,类型为ListCollectionView。        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.mainGrid.DataContext);        listView.CurrentChanged += listView_CurrentChanged;        this.showLbl.Text = (listView.CurrentPosition + 1).ToString() + "/" + listView.Count.ToString();    }    //数据视图的CurrentChanged事件。    void listView_CurrentChanged(object sender, EventArgs e)    {        this.showLbl.Text = (listView.CurrentPosition + 1).ToString() + "/" + listView.Count.ToString();        btnNext.IsEnabled = this.listView.CurrentPosition < listView.Count - 1;        btnPrevious.IsEnabled = this.listView.CurrentPosition > 0;    }    //MoveCurrentToNext()方法。    private void btnNext_Click(object sender, RoutedEventArgs e)    {        //点击按钮,移动到下一条记录上。        listView.MoveCurrentToNext();    }    //MoveCurrentToPrevious()方法。    private void btnPrevious_Click(object sender, RoutedEventArgs e)    {        //点击按钮,移动到上一条记录上。        listView.MoveCurrentToPrevious();    }}
View Code

效果图:

5、ComBoBox的IsSynchronizedWithCurrentItem属性,选择项同步问题。

xml代码:

产品编号:
产品名字:
产品价格:
产品描述:
产品图片:
View Code

后台代码:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    //声明一个视图。    private ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.comboBox1.ItemsSource = productBll.GetCollectionProduct();        //通过GetDefaultView()方法获取数据视图,类型为ListCollectionView。        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.comboBox1.ItemsSource);        listView.CurrentChanged += listView_CurrentChanged;        this.showLbl.Text = (listView.CurrentPosition + 1).ToString() + "/" + listView.Count.ToString();    }    //数据视图的CurrentChanged事件。    void listView_CurrentChanged(object sender, EventArgs e)    {        this.showLbl.Text = (listView.CurrentPosition + 1).ToString() + "/" + listView.Count.ToString();        btnNext.IsEnabled = this.listView.CurrentPosition < listView.Count - 1;        btnPrevious.IsEnabled = this.listView.CurrentPosition > 0;    }    //MoveCurrentToNext()方法。    private void btnNext_Click(object sender, RoutedEventArgs e)    {        //点击按钮,移动到下一条记录上。        listView.MoveCurrentToNext();    }    //MoveCurrentToPrevious()方法。    private void btnPrevious_Click(object sender, RoutedEventArgs e)    {        //点击按钮,移动到上一条记录上。        listView.MoveCurrentToPrevious();    }}
View Code

效果图:

 

这个时候需要设置ComBoBox的IsSynchronizedWithCurrentItem属性为true。

再看效果图:

 6、过滤(Filter)。

在将集合用作数据源时,可使用视对象的Filter属性设置过滤器。过滤器会检查集合中的的每个数据项,如果被检查的项满足过滤条件,就返回True,否则返回false。

6.1)、普通过滤。

后台代码:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    //声明视图。    ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetCollectionProduct();        //将集合用作数据源。可以通过视图进行过滤。        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        listView.Filter = new Predicate(FileterProduct);    }    //过滤。    private bool FileterProduct(object obj)    {        //转换成对象。        Models.Product product = (Models.Product)obj;        //返回价格大于8块的商品。        return (product.ProPrice > 8);    }}

效果图:

 

6.2)、手动设置过滤条件。

xml代码: 

价格>=
产品编号:
产品名称:
产品价格:
产品描述:
产品图片:
View Code

后台代码:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    //声明视图。    ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetCollectionProduct();        //将集合用作数据源。可以通过视图进行过滤。        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        listView.Filter = new Predicate(FileterProduct);    }    //过滤。    private bool FileterProduct(object obj)    {        //转换成对象。        Models.Product product = (Models.Product)obj;        //返回价格大于5块的商品。        return (product.ProPrice > Convert.ToInt32(this.priceFilter.Text));    }      //过滤。    private void btnFilter_Click(object sender, RoutedEventArgs e)    {        //交换机、电脑、小盒子(配置稍微好一点)        //用委托。        listView.Filter += new Predicate(delegate(object obj)         {            //转换成Product对象。            Models.Product product = (Models.Product)obj;            //返回true或false。            return (product.ProPrice > Convert.ToInt32(this.priceFilter.Text));        });        //也可用Lambda表达式。        //listView.Filter += new Predicate((object obj) =>         //{        //    //转换成Product对象。        //    Models.Product product = (Models.Product)obj;        //    //返回true或false。        //    return (product.ProPrice > Convert.ToInt32(this.priceFilter.Text));        //});                    }}
View Code

效果图:

6.3、手动编写过滤器的类。

ProductByPriceFilter类:

/// /// 价格过滤类。/// public class ProductByPriceFilter{    ///     /// 最低价。    ///     public decimal MinimumPrice { get; set; }    public ProductByPriceFilter(decimal _minimunPrice)    {        //为属性赋值。        MinimumPrice = _minimunPrice;    }    ///     /// 此方法用于过滤。    ///     /// 过滤的集合中的每一项。    /// 
public bool FilterItem(object _item) { //将集合中的项转换成Product对象。 Models.Product product = (Models.Product)_item; if (product != null) { return product.ProPrice > MinimumPrice; } else { return false; } }}
View Code

后台代码:

private void btnFilter_Click(object sender, RoutedEventArgs e){    decimal minimumPrice;    if(Decimal.TryParse(priceFilter.Text,out minimumPrice))    {        if (listView != null)        {            //实例化ProductByPriceFilter对象。            ProductByPriceFilter proFilter = new ProductByPriceFilter(minimumPrice);            //过滤。            listView.Filter = new Predicate(proFilter.FilterItem);        }    }}

效果和之前一样。

6.4)、删除过滤器。

设置Filter属性=null即可删除过滤器。

7、过滤DataTable对象。

对于DataTable对象,过滤工作是不同的,如果以前使用过ADO.Net,可能已经知道每个DataTable对象都与一个DataView对象相关联。 与ListCollectionView不同的是,DataTable对象使用的是BindingListCollectionView视图,此时图不支持Filter属性,但BindingListCollectionView提供了CustomeFilter属性,CustomeFilter属性本身不能做任何工作,只是接收指定的过滤字符串,并使用这个过滤字符串设置DataView.RowFilter属性。使用DataViewRowFilter属性非常容易,但有点混乱。将基于字符串的过滤器表达式作为参数,这个表达式类似于Select查询中构造Where子句的代码块,要遵守所有的SQL约定,如果希望使用多个条件,需要使用 or 或 and 关键字将这些条件结合在一起。

Xaml代码: 

产品编号:
产品名称:
产品价格:
产品描述:
产品图片:
View Code

后台代码: 

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    //新建bindingListCollectionView对象。    BindingListCollectionView bindingListCollectionView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetDataTable().DefaultView;        //将数据源转换成BindingListCollectionView对象,而不是ListCollectionView。        bindingListCollectionView = (BindingListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        if (bindingListCollectionView != null)        {            //通过CustomFilter属性,过滤条件,过滤价格 > 5的用户。            bindingListCollectionView.CustomFilter = "ProPrice > 5 ";            //多个条件。            //bindingListCollectionView.CustomFilter = "ProPrice > 5 and ProId < 10 ";        }    }}

 效果图:

8、排序。

可以通过视图进行排序,最简单的方式是根据每个数据项中的一个或多个属性的值进行排序。使用System.ComponentModel.SortDescription对象确定希望使用的字段。每个DortDescription对象确定希望用于排序的字段和排序方向(升序或降序)。

后台代码: 

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    //新建bindingListCollectionView对象。    BindingListCollectionView bindingListCollectionView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetDataTable().DefaultView;        //将数据源转换成BindingListCollectionView对象,而不是ListCollectionView。        bindingListCollectionView = (BindingListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        if (bindingListCollectionView != null)        {            //通过CustomFilter属性,过滤条件,过滤价格 > 5的用户。            bindingListCollectionView.CustomFilter = "ProPrice > 5 ";            //多个条件。            //bindingListCollectionView.CustomFilter = "ProPrice > 5 and ProId < 10 ";            //通过SortDescriptions属性添加排序,实例化SortDescription添加字段和升序降序操作。            bindingListCollectionView.SortDescriptions.Add(new System.ComponentModel.SortDescription("ProId", System.ComponentModel.ListSortDirection.Descending));        }    }}

9、自定义排序。

自定义排序只能应用于ListCollectionView视图,不能应用于BindingListCollectionView。ListCollectionView类提供的Custome属性接收一个ICompaer对象,ICompare对象在两个数据项之间进行比较,并且指示较大项。如果需要构建组合多个属性来得到排序键的排列例程,这种方法是非常的有用。

 xaml代码:

产品编号:
产品名称:
产品价格:
产品描述:
产品图片:
View Code

SortByProNameLength类:

//实现自定义排序的步骤://1、新建1个类,继承IComparer接口。//2、实现接口中的Compare()方法。//3、实例化SortByProNameLength实例时,代码需要提供使用的名称(作为字符串),之后Compare方法可以使用反射在数据对象中查找该属性。public class SortByProNameLength:IComparer{    public int Compare(object x, object y)    {        Models.Product ProductX = (Models.Product)x;        Models.Product ProductY = (Models.Product)y;        return ProductX.ProName.Length.CompareTo(ProductY.ProName.Length);    }}
View Code

后台代码:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetCollectionProduct2();        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        if (listView != null)        {            //实例化SortByProNameLength对象。            listView.CustomSort = new SortByProNameLength();        }    }}

效果图:

10)、分组。

与排序的方式相同,视图也支持分组。与排序一样,可使用简单的方式进行分组(根据单个属性值),也可以使用复杂的方式进行分组(使用自定义的回调函数)。为执行分组,需要为CollectionView.GroupDescriptions集合添加System.ComponentMode.PropertyGroupDescription对象。

后台代码:前台不变:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetCollectionProduct2();        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        if (listView != null)        {            //根据商品名称进行分组。            listView.GroupDescriptions.Add(new PropertyGroupDescription("ProName"));        }    }}

 效果图:

根据上图可以看出:尽管现在数据项根据产品名字安排到不同的分组中,但当查看列表时,很难发现已经应用到了任何分组,但是,该例发生了更多变化--只是默认情况下看不到这些变化。当使用分组时,列表会为每个分组创建单独的GroupItem对象,并且为列表添加了这些GroupItem对象。GroupItem是内容控件,所以每个GroupItem对象都包含了一个适当的具有实际数据的容器(如ListBoxItem对象)。显示分组的秘密是格式化GroupItem元素,使其突出。可使用样式为列表中的所有GroupItem对象引用格式,如果希望显示分组标题,就需要使用模板了。幸运的是,ItemsControl类通过它的ItemsControl.GroupStyle属性简化了这两项任务,该属性提供了一个GroupStyle对象的集合,虽然名称中包含了"Style",但GroupStyle并不是样式。只是一个简单的包,以下是GroupStyle的属性。

GruopStyle类的常用属性

ContainerStyle

设置应用到为每个分组生成的GroupItem元素的样式。

ContainerStyleSelector

不是使用ContainerStyle属性,反而可以使用ContainerStyleSelector属性提供一个类,该类根据分组选择准备使用的正确的样式。

HeaderTemplate

允许用户在每个分组开头显示内容创建模板。

HeaderTemplateSelector

不是使用HeaderTemplate属性,而是可以使用HeaderTemplateSelector属性提供一个类,根据分组选择正确的模板。

Panel

用于改变分组的模板。

 

 

 

 

 

 

 

 

 

 

10.1)、添加分组标记。

添加分组标题,需要设置GroupStyle.HeadTemplate属性,可以使用普通的数据模板进行填充,当编写表达式时,不能绑定到列表中的数据对象(在这个示例中是Product对象),而是要绑定到分组的PropertyGroupDescription对象,需要绑定PropertyGroupDescription.Name属性,而不是绑定Product.ProName属性。

XAML代码: 

后台代码:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetCollectionProduct2();        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        if (listView != null)        {            listView.GroupDescriptions.Add(new PropertyGroupDescription("ProName"));        }    }}

效果图:

10.2)、分组和排序一块使用。 

改动的Xaml代码: 

后台代码:

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;        ListCollectionView listView;        void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetCollectionProduct2();        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        if (listView != null)        {            //根据产品名称进行分组。            listView.GroupDescriptions.Add(new PropertyGroupDescription("ProName"));            //根据产品价格进行分组。            listView.SortDescriptions.Add(new System.ComponentModel.SortDescription("ProPrice", System.ComponentModel.ListSortDirection.Descending));        }    }}

 效果图:

10.3)、放到概念组中。

如果根据价钱来进行分组,那么不同的价钱会建立一个分组,可以通过创建值转换器类来进行分组。如100到150之间、150到200之间。

新建PriceRangeProductGrouper类:

public class PriceRangeProductGrouper:IValueConverter{    //分组范围。    public int GroupInterval { get; set; }    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)    {        decimal price = (decimal)value;        if (price < GroupInterval)        {            return string.Format(culture, "小于{0:C}的分组", GroupInterval);        }        else        {            int interval = (int)price / GroupInterval;            int lowerLimit = interval * GroupInterval;            int upperLimit = (interval + 1) * GroupInterval;            return string.Format(culture, "{0:C}到{1:C}之间的分组", lowerLimit, upperLimit);        }    }    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)    {        throw new NotImplementedException();    }}

 Xaml代码不变,后台代码: 

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();        this.Loaded += MainWindow_Loaded;    }    Bll.ProductBll productBll = App.ProductBll;    ListCollectionView listView;    void MainWindow_Loaded(object sender, RoutedEventArgs e)    {        this.listBox1.ItemsSource = productBll.GetCollectionProduct2();        listView = (ListCollectionView)CollectionViewSource.GetDefaultView(this.listBox1.ItemsSource);        if (listView != null)        {               //实例化PriceRangeProductGrouper类。            PriceRangeProductGrouper grouper = new PriceRangeProductGrouper(50);            //传入参数。            listView.GroupDescriptions.Add(new PropertyGroupDescription("ProPrice", grouper));        }    }} 

效果图:

End!

转载地址:http://djweo.baihongyu.com/

你可能感兴趣的文章
注册特殊广播接收者
查看>>
matplotlib正弦和余弦图
查看>>
DataTable的用法
查看>>
教育部老师远程培训课程听课点击器
查看>>
表操作汇总(复制,删除,修改,插入,查询及数据库的复制)
查看>>
redis 基本数据类型-列表(List)
查看>>
H5开发推荐使用Q.js,轻量的前端单页路由框架
查看>>
一些简单的递归算法
查看>>
list切片的补充
查看>>
pdf生成库-libharu编译
查看>>
[Python]处理windows下多级目录文件,上传到Linux服务器
查看>>
java enum用法
查看>>
3月11日工作日志
查看>>
弹性盒布局(flex)
查看>>
《梦断代码》读后笔记_1
查看>>
设计模式学习笔记之责任链模式
查看>>
1597: [Usaco2008 Mar]土地购买
查看>>
Oracle数值处理函数 (绝对值、取整...)
查看>>
年薪10W和100w的人差距在哪?
查看>>
Redis的集群安装以及rehash重新迁移教程指南
查看>>