数据视图

简介: 原文:数据视图1、数据视图。 使用数据视图,可添加导航逻辑并实现过滤、排序和分组。 2、View对象。 当将结合(或DataTable)绑定到ItemsControl控件时,会不加通告地在后台创建数据视图---位于数据源和绑定的控件之间。
原文: 数据视图

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代码:

            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品编号:</TextBlock>
        <TextBox Grid.Row="0" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProId}"></TextBox>
        <TextBlock Grid.Row="1" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品名字:</TextBlock>
        <TextBox Grid.Row="1" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProName}"></TextBox>
        <TextBlock Grid.Row="2" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品价格:</TextBlock>
        <TextBox Grid.Row="2" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProPrice, StringFormat={}{0:C}}"></TextBox>
        <TextBlock Grid.Row="3" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品描述:</TextBlock>
        <TextBox Grid.Row="3" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProDescribe}"></TextBox>
        <TextBlock Grid.Row="4" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品图片:</TextBlock>
        <Image Grid.Row="4" Grid.Column="1">
            <Image.Source>
                <Binding Path="ProImagePath">
                    <Binding.Converter>
                        <local:ImagePathConverter></local:ImagePathConverter>
                    </Binding.Converter>
                </Binding>
            </Image.Source>
        </Image>
        <Button Name="btnPrevious" Click="btnPrevious_Click" Grid.Row="5" Grid.Column="0" FontSize="30" FontWeight="Bold" Width="30" Content="&lt;"></Button>            
        <TextBlock Name="showLbl" Grid.Row="5" FontSize="20" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.ColumnSpan="2"></TextBlock>            
        <Button Name="btnNext" Grid.Row="5" Grid.Column="1" FontSize="30" FontWeight="Bold" Width="30" Content="&gt;" Click="btnNext_Click"></Button>
    </Grid>
</Border>
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代码:

<Border CornerRadius="5" Background="SteelBlue">
    <Grid Name="mainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>                
        </Grid.RowDefinitions>          
        <ComboBox Grid.Row="0" Margin="10" Name="comboBox1" DisplayMemberPath="ProName"></ComboBox>  

        <Grid Grid.Row="1" DataContext="{Binding ElementName=comboBox1, Path=SelectedItem}">                
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            
            <Grid.RowDefinitions>
                <RowDefinition Height="50"></RowDefinition>
                <RowDefinition Height="50"></RowDefinition>
                <RowDefinition Height="50"></RowDefinition>
                <RowDefinition Height="50"></RowDefinition>
                <RowDefinition Height="100"></RowDefinition>
                <RowDefinition Height="50"></RowDefinition>
            </Grid.RowDefinitions>

            <TextBlock Grid.Row="0" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品编号:</TextBlock>
            <TextBox Grid.Row="0" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProId}"></TextBox>
            <TextBlock Grid.Row="1" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品名字:</TextBlock>
            <TextBox Grid.Row="1" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProName}"></TextBox>
            <TextBlock Grid.Row="2" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品价格:</TextBlock>
            <TextBox Grid.Row="2" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProPrice, StringFormat={}{0:C}}"></TextBox>
            <TextBlock Grid.Row="3" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品描述:</TextBlock>
            <TextBox Grid.Row="3" Grid.Column="1" FontSize="20" Height="30" Width="200" HorizontalAlignment="Left" Text="{Binding Path=ProDescribe}"></TextBox>
            <TextBlock Grid.Row="4" Grid.Column="0"  Foreground="White" HorizontalAlignment="Right" VerticalAlignment="Center" FontSize="20">产品图片:</TextBlock>
            <Image Grid.Row="4" Grid.Column="1" Source="{Binding Path=ProImagePath, Converter={StaticResource ResourceKey=ImagePathConverter}}"></Image>
            <Button Name="btnPrevious" Click="btnPrevious_Click" Grid.Row="5" Grid.Column="0" FontSize="30" FontWeight="Bold" Width="30" Content="&lt;"></Button>            
            <TextBlock Name="showLbl" Grid.Row="5" FontSize="20" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.ColumnSpan="2"></TextBlock>            
            <Button Name="btnNext" Grid.Row="5" Grid.Column="1" FontSize="30" FontWeight="Bold" Width="30" Content="&gt;" Click="btnNext_Click"></Button>
        </Grid>
    </Grid>
</Border>
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。

<ComboBox Grid.Row="0" Margin="10" Name="comboBox1" DisplayMemberPath="ProName" IsSynchronizedWithCurrentItem="True"> </ComboBox>

再看效果图:

 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<object>(FileterProduct);
    }
    //过滤。
    private bool FileterProduct(object obj)
    {
        //转换成对象。
        Models.Product product = (Models.Product)obj;
        //返回价格大于8块的商品。
        return (product.ProPrice > 8);
    }
}

效果图:

 

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

xml代码: 

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition Width="2*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    
    <Grid ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="3*"></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <ListBox Name="listBox1" HorizontalContentAlignment="Stretch" FontSize="20" DisplayMemberPath="ProName"></ListBox>
        <TextBlock Grid.Row="1" FontSize="20" VerticalAlignment="Center">价格>= </TextBlock> 
        <TextBox Name="priceFilter" Grid.Row="1" HorizontalAlignment="Right" FontSize="20" VerticalAlignment="Center" Text="0" Width="90"></TextBox>
        <Button Grid.Row="2" Margin="10" Content="点击过滤" Name="btnFilter" Click="btnFilter_Click"></Button>
    </Grid>
    
    <Grid Grid.Column="1" ShowGridLines="True" DataContext="{Binding ElementName=listBox1, Path=SelectedItem}">
        <Border CornerRadius="10">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition Height="2*"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition Width="2*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock FontSize="20" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center">产品编号:</TextBlock>
                <TextBox FontSize="20" Grid.Row="0" Grid.Column="1" Height="30" Text="{Binding Path=ProId}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center">产品名称:</TextBlock>
                <TextBox FontSize="20" Grid.Row="1" Grid.Column="1" Height="30" Text="{Binding Path=ProName}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Center">产品价格:</TextBlock>
                <TextBox FontSize="20" Grid.Row="2" Grid.Column="1" Height="30" Text="{Binding Path=ProPrice, StringFormat={}{0:C}}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="3" HorizontalAlignment="Right" VerticalAlignment="Center">产品描述:</TextBlock>
                <TextBox FontSize="20" Grid.Row="3" Grid.Column="1" Height="30" Text="{Binding Path=ProDescribe}"></TextBox>
                <TextBox FontSize="20" Grid.Row="3" Grid.Column="1" Height="30" Text="{Binding Path=ProImagePath}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="4" HorizontalAlignment="Right" VerticalAlignment="Center">产品图片:</TextBlock>
                <Image Grid.Row="4" Grid.Column="1" Source="{Binding Path=ProImagePath, Converter={StaticResource ImagePathConverter1}}"></Image>
            </Grid>
        </Border>
    </Grid>
</Grid>
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<object>(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<object>(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>((object obj) => 
        //{
        //    //转换成Product对象。
        //    Models.Product product = (Models.Product)obj;
        //    //返回true或false。
        //    return (product.ProPrice > Convert.ToInt32(this.priceFilter.Text));
        //});                
    }
}
View Code

效果图:

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

ProductByPriceFilter类:

/// <summary>
/// 价格过滤类。
/// </summary>
public class ProductByPriceFilter
{
    /// <summary>
    /// 最低价。
    /// </summary>
    public decimal MinimumPrice { get; set; }

    public ProductByPriceFilter(decimal _minimunPrice)
    {
        //为属性赋值。
        MinimumPrice = _minimunPrice;
    }

    /// <summary>
    /// 此方法用于过滤。
    /// </summary>
    /// <param name="_item">过滤的集合中的每一项。</param>
    /// <returns></returns>
    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<object>(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代码: 

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition Width="2*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    
    <ListBox Name="listBox1" HorizontalContentAlignment="Stretch" FontSize="20" DisplayMemberPath="ProName"></ListBox>

    <Grid Grid.Column="1" DataContext="{Binding ElementName=listBox1, Path=SelectedItem}">
        <Border CornerRadius="10">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition Height="2*"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition Width="2*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock FontSize="20" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center">产品编号:</TextBlock>
                <TextBox FontSize="20" Grid.Row="0" Grid.Column="1" Height="30" Text="{Binding Path=ProId}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center">产品名称:</TextBlock>
                <TextBox FontSize="20" Grid.Row="1" Grid.Column="1" Height="30" Text="{Binding Path=ProName}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Center">产品价格:</TextBlock>
                <TextBox FontSize="20" Grid.Row="2" Grid.Column="1" Height="30" Text="{Binding Path=ProPrice, StringFormat={}{0:C}}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="3" HorizontalAlignment="Right" VerticalAlignment="Center">产品描述:</TextBlock>
                <TextBox FontSize="20" Grid.Row="3" Grid.Column="1" Height="30" Text="{Binding Path=ProDescribe}"></TextBox>
                <TextBox FontSize="20" Grid.Row="3" Grid.Column="1" Height="30" Text="{Binding Path=ProImagePath}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="4" HorizontalAlignment="Right" VerticalAlignment="Center">产品图片:</TextBlock>
                <Image Grid.Row="4" Grid.Column="1" Source="{Binding Path=ProImagePath, Converter={StaticResource ImagePathConverter1}}"></Image>
            </Grid>
        </Border>
    </Grid>
</Grid>
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代码:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition Width="2*"></ColumnDefinition>
    </Grid.ColumnDefinitions>

    <ListBox Name="listBox1" HorizontalContentAlignment="Stretch" FontSize="20" DisplayMemberPath="ProName"></ListBox>

    <Grid Grid.Column="1" DataContext="{Binding ElementName=listBox1, Path=SelectedItem}">
        <Border CornerRadius="10">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition Height="2*"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition Width="2*"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock FontSize="20" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center">产品编号:</TextBlock>
                <TextBox FontSize="20" Grid.Row="0" Grid.Column="1" Height="30" Text="{Binding Path=ProId}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center">产品名称:</TextBlock>
                <TextBox FontSize="20" Grid.Row="1" Grid.Column="1" Height="30" Text="{Binding Path=ProName}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="2" HorizontalAlignment="Right" VerticalAlignment="Center">产品价格:</TextBlock>
                <TextBox FontSize="20" Grid.Row="2" Grid.Column="1" Height="30" Text="{Binding Path=ProPrice, StringFormat={}{0:C}}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="3" HorizontalAlignment="Right" VerticalAlignment="Center">产品描述:</TextBlock>
                <TextBox FontSize="20" Grid.Row="3" Grid.Column="1" Height="30" Text="{Binding Path=ProDescribe}"></TextBox>
                <TextBox FontSize="20" Grid.Row="3" Grid.Column="1" Height="30" Text="{Binding Path=ProImagePath}"></TextBox>
                <TextBlock FontSize="20" Grid.Row="4" HorizontalAlignment="Right" VerticalAlignment="Center">产品图片:</TextBlock>
                <Image Grid.Row="4" Grid.Column="1" Source="{Binding Path=ProImagePath, Converter={StaticResource ImagePathConverter1}}"></Image>
            </Grid>
        </Border>
    </Grid>
</Grid>
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代码: 

<ListBox Name="listBox1" HorizontalContentAlignment="Stretch" FontSize="20" DisplayMemberPath="ProName">
    <ListBox.GroupStyle> 
        <GroupStyle>
            <!--设置HeaderTemplate-->
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <!--在这里绑定的是PropertyGroupDescription.Name属性-->
                    <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Foreground="White" Background="LightGreen"></TextBlock>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </ListBox.GroupStyle>            
</ListBox>

后台代码:

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代码: 

<ListBox Name="listBox1" HorizontalContentAlignment="Stretch" FontSize="20">            
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition></ColumnDefinition>
                    <ColumnDefinition></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Path=ProName}"></TextBlock>
                <TextBlock Grid.Column="1" Text="{Binding Path=ProPrice, StringFormat={}{0:C}}"></TextBlock>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
    
    <ListBox.GroupStyle>
        <GroupStyle>
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Foreground="White" Background="LightGreen"></TextBlock>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </ListBox.GroupStyle>            
</ListBox>

后台代码:

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!

目录
相关文章
|
4月前
|
SQL 存储 BI
什么是视图?详细解析与应用指南
【8月更文挑战第31天】
842 0
|
7月前
|
SQL 存储 安全
|
SQL 存储 关系型数据库
第14章_视图
第14章_视图
93 0
|
7月前
|
存储 算法 关系型数据库
了解并使用视图
【1月更文挑战第13天】了解并使用视图。
66 1
|
7月前
|
SQL 前端开发 安全
视图的作用
视图的作用。
74 1
|
编解码 Android开发
视图 总结 基础
DragViewTaskRelease 使用FrameLayout布局(可以用其他的),内嵌imageView实现悬浮拖动和点击事件,继承View的ontouchEvent进行动作监听和移动 getX(),getY()等方法的区别(图解) BarPercentView 条形进度条(可设置 线性渐变-背景色-进度条颜色-进度条高度) 游戏下载进度条显示 zidingyiView矩形进度框,在构造函数里定义基础属性,初始化布局,定义俩个矩形,onMeasure获取宽高和onDraw方法显示
|
SQL 数据处理
视图的创建
如何创建和使用视图的功能,更好的方便我们的工作。
116 0
|
存储
视图
视图
126 0
|
监控 中间件 程序员
关于开发视图
开发视图是逻辑视图的实现,它又叫实现视图,描述了在开发环境中软件的静态组织结构,主要侧重于软件模块的组织和管理。
730 0
关于开发视图