使用ICollectionView.Filter对ObservableCollection筛选

前提:以前对于ObservableCollection的筛选都是在viewmodel里面添加一个额外属性(例如Visibility或者bool来控制元素的显示隐藏)。
下面例子是用MVVMlight框架的,先上xaml代码

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        x:Class="WpfApp.MainWindow"
        mc:Ignorable="d" DataContext="{Binding Main,Source={StaticResource Locator}}"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <Style TargetType="DataGridRow">
            <Setter Property="Visibility" Value="{Binding Visibility}"></Setter>
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <Setter Property="Background" Value="Transparent" />
                </Trigger>
                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="#F8F8F8" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <DataGrid ItemsSource="{Binding Students}">
            <DataGrid.Columns>
                <DataGridTextColumn Width="*" ElementStyle="{StaticResource CenterAlignmentStyle}" Header="ID" Binding="{Binding ID}"></DataGridTextColumn>
                <DataGridTextColumn Width="*" ElementStyle="{StaticResource CenterAlignmentStyle}" Header="姓名" Binding="{Binding Name}"></DataGridTextColumn>
                <DataGridTextColumn Width="*" ElementStyle="{StaticResource CenterAlignmentStyle}" Header="年龄" Binding="{Binding Age}"></DataGridTextColumn>
                <DataGridTextColumn Width="*" ElementStyle="{StaticResource CenterAlignmentStyle}" Header="班级" Binding="{Binding ClsName}"></DataGridTextColumn>
                <DataGridTextColumn Width="*" ElementStyle="{StaticResource CenterAlignmentStyle}" Header="学校" Binding="{Binding SchoolName}"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
        <WrapPanel>
            <Label Content="姓名:" VerticalContentAlignment="Center"></Label>
            <TextBox Width="100" x:Name="TbName" VerticalContentAlignment="Center"></TextBox>
            <Button Content="筛选" Height="30" Width="100" Command="{Binding FilterCommand}" CommandParameter="{Binding ElementName=TbName,Path=Text}"></Button>
            <Button Content="重置" Height="30" Width="100" Command="{Binding ClearFilterCommand}"></Button>
        </WrapPanel>
    </StackPanel>

</Window>

以前思路的viewmodel代码在

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace WpfApp.ViewModel
{
    /// 
    /// This class contains properties that the main View can data bind to.
    /// 
    /// Use the mvvminpc snippet to add bindable properties to this ViewModel.
    /// 
    /// 
    /// You can also use Blend to data bind with the tool's support.
    /// 
    /// 
    /// See http://www.galasoft.ch/mvvm
    /// 
    /// 
    public class MainViewModel : ViewModelBase
    {
        public ObservableCollection<Student> Students { get; set; }

        public ICommand FilterCommand { get; private set; }

        public ICommand ClearFilterCommand { get; private set; }

        public MainViewModel()
        {
            Students = new ObservableCollection<Student>() {
                    new Student(){ ID  = 1,Name ="小王",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 2,Name ="小张",Age = 12 , ClsName ="五班",SchoolName ="北大"},
                    new Student(){ ID  = 3,Name ="小韩",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 4,Name ="小李",Age = 15 , ClsName ="二班",SchoolName ="哈佛"},
                    new Student(){ ID  = 5,Name ="小朱",Age = 13 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 6,Name ="小桂",Age = 12 , ClsName ="一班",SchoolName ="湖大"},
                    new Student(){ ID  = 7,Name ="小肖",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 8,Name ="小钱",Age = 11 , ClsName ="三班",SchoolName ="交大"},
                    new Student(){ ID  = 9,Name ="小孙",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 10,Name ="小宋",Age = 12 , ClsName ="四班",SchoolName ="清华"},
               };

            FilterCommand = new RelayCommand<string>((name) =>
            {
                foreach (var student in Students)
                {
                    student.Visibility = student.Name == name ? Visibility.Visible : Visibility.Collapsed;
                }
            });

            ClearFilterCommand = new RelayCommand(() =>
            {
                foreach (var student in Students)
                {
                    student.Visibility = Visibility.Visible;
                }
            });
        }
    }

    public class Student : ViewModelBase
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }

        public string ClsName { get; set; }

        public string SchoolName { get; set; }

        private Visibility _visibility = Visibility.Visible;
        public Visibility Visibility { get { return _visibility; } set { Set(ref _visibility, value); } }

    }
}

当然 也可以定义一个bool属性,然后用转换器转为Visibility ;
使用ICollectionView后 代码:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace WpfApp.ViewModel
{
    /// 
    /// This class contains properties that the main View can data bind to.
    /// 
    /// Use the mvvminpc snippet to add bindable properties to this ViewModel.
    /// 
    /// 
    /// You can also use Blend to data bind with the tool's support.
    /// 
    /// 
    /// See http://www.galasoft.ch/mvvm
    /// 
    /// 
    public class MainViewModel : ViewModelBase
    {
        public ObservableCollection<Student> Students { get; set; }

        public ICommand FilterCommand { get; private set; }

        public ICommand ClearFilterCommand { get; private set; }

        private ICollectionView collectionView
        {
            get
            {
                return CollectionViewSource.GetDefaultView(Students);
            }
        }

        public MainViewModel()
        {
            Students = new ObservableCollection<Student>() {
                    new Student(){ ID  = 1,Name ="小王",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 2,Name ="小张",Age = 12 , ClsName ="五班",SchoolName ="北大"},
                    new Student(){ ID  = 3,Name ="小韩",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 4,Name ="小李",Age = 15 , ClsName ="二班",SchoolName ="哈佛"},
                    new Student(){ ID  = 5,Name ="小朱",Age = 13 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 6,Name ="小桂",Age = 12 , ClsName ="一班",SchoolName ="湖大"},
                    new Student(){ ID  = 7,Name ="小肖",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 8,Name ="小钱",Age = 11 , ClsName ="三班",SchoolName ="交大"},
                    new Student(){ ID  = 9,Name ="小孙",Age = 12 , ClsName ="二班",SchoolName ="清华"},
                    new Student(){ ID  = 10,Name ="小宋",Age = 12 , ClsName ="四班",SchoolName ="清华"},
               };

            FilterCommand = new RelayCommand<string>((name) =>
            {
                collectionView.Filter = x => x is Student stu && stu.Name == name;
            });

            ClearFilterCommand = new RelayCommand(() =>
            {
				collectionView.Filter = x => true;
            });
        }
    }

    public class Student
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }

        public string ClsName { get; set; }

        public string SchoolName { get; set; }
    }
}

看下前后对比就知道了,基础Model不用继承ViewModel了,因为不用修改属性来更改UI了。
前后代码运行结果都是一样的,本文只是做一个简单实验,写的不好,多见谅!
附赠一个扩展方法,这样就可以把过滤条件封装起来啦:

原先的:
	collectionView.Filter = x => x is Student stu && stu.Name == name;
新的:
	collectionView.Filter = predicate(name).ToObject();
    public static Predicate<object> ToObject<TFrom>(this Predicate<TFrom> predicate) {
         return x => x is TFrom from && predicate.Invoke(from);
    }
    private Predicate<Student> predicate(string name) {
   		return x => x.Name == name;
    }

你可能感兴趣的:(使用ICollectionView.Filter对ObservableCollection筛选)