如何为集合设计多重筛选器
本文关键字:筛选 集合 | 更新日期: 2023-09-27 18:28:30
我的型号:
public class Person
{
public string Name { get; set; }
public bool Sex { get; set; }
public string Country { get; set; }
}
在我的WPF应用程序中,我想将列表绑定到DataGridControl,该视图还支持按性别和国家筛选。
我目前的解决方案是创建一个List PersonList来存储所有数据,并创建另一个List PersonBindingList来存储应该在UI中显示的数据。当用户检查过滤器并单击"确定"时,使用Linq从PersonList进行查询,并将结果分配给PersonBindingList以更新UI。
但这应该保留两个列表。此外,我不想每次用户更改过滤条件时都加载数据,因为数据量非常大,加载速度非常慢。还有其他解决方案吗?还有一件事,《性与乡村》可以自由结合。
感谢
如果您想在客户端过滤数据,ICollectionView
(特别是ListCollectionView
)就是您想要的:
public class ViewModel
{
// this is a property for filtering
public bool Sex
{
get { ... }
set
{
if (_sex != value)
{
_sex = value;
OnPropertyChanged();
PersonListView.Refresh();
}
}
}
// this is a property for filtering too
public string Country
{
// call PersonListView.Refresh in setter, as in Sex property setter
}
// this is a property for binding to DataGrid
public ICollectionView PersonListView
{
get
{
if (_personListView == null)
{
_personList = LoadPersons();
_personListView = new ListCollectionView(_personList)
{
Filter = p => ShouldViewPerson((Person)p);
}
}
return _personListView;
}
}
private bool ShouldViewPerson(Person p)
{
// implement filtering logic here;
// e.g.:
return p.Country.StartsWith(Country) && p.Sex == Sex;
}
private ListCollectionView _personListView;
private List<Person> _personList;
}
集合视图是某种投影,用于对源集合/序列进行排序、筛选和分组。您可以将它们视为LINQ的Where
、GroupBy
、OrderBy
和Select
方法的组合,这些方法将应用于源集合,以及将绑定到视图的结果序列。
默认情况下,若您从视图模型中公开某个集合,数据绑定引擎将为您创建默认的集合视图。但是,如果您想获得自定义行为,比如过滤,您可以自己构建集合视图,并公开它而不是集合。
我不希望每次用户更改筛选器时都加载数据条件下,由于数据量非常大,加载速度非常慢
如果可以,可以考虑在服务器端进行筛选。客户端过滤是在内存中执行的,可能会消耗大量系统资源。
更新
如果您希望从筛选列表中多选国家/地区,可以将标量Country
属性替换为Countries
集合,并重新编写筛选逻辑。类似这样的东西:
// this is a filter item
public class CountryFilterItem : INotifyPropertyChanged
{
public string CountryName { ... }
public bool IsChecked { ... }
}
public class ViewModel
{
// this property is a replacement for "Country";
// bind it to some ItemsControl is the filter view
public IEnumerable<CountryFilterItem> Countries
{
get { return _countries; }
}
// fill filter somewhere;
// when filling, subscribe on `PropertyChanged` event of each item;
// when user will change IsChecked for item, you'll update filter:
//
// var country = new Country { CountryName = "Zimbabwe" };
// country.PropertyChanged += (sender, args) =>
// {
// if (propertyName == "IsChecked")
// {
// PersonListView.Refresh();
// }
// };
// _countries.Add(country);
private List<CountryFilterItem> _countries;
// filtering logic
private bool ShouldViewPerson(Person p)
{
// implement filtering logic here;
// e.g.:
return _countries.Any(_ => _.IsChecked && _.CountryName == p.Country) && p.Sex == Sex;
}
// other code here...
}