前提:以前对于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;
}