c# - 如何为集合设计多重过滤器

标签 c# wpf algorithm data-structures data-binding

我的模型:

public class Person
{
    public string Name { get; set; }
    public bool Sex { get; set; }
    public string Country { get; set; }
}

在我的 WPF 应用程序中,我想将一个列表绑定(bind)到 DataGridControl,该 View 还支持按性别和国家/地区进行过滤。

我当前的解决方案是创建一个列表 PersonList 来存储所有数据,并创建另一个列表 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;
}

Collection View 是某种投影,用于对源集合/序列进行排序、过滤和分组。您可以将它们视为 LINQ 的 WhereGroupByOrderBySelect 方法的组合,即应用于将绑定(bind)到 View 的源集合和结果序列。

默认情况下,如果您从 View 模型中公开某些集合,数据绑定(bind)引擎会为您创建默认 Collection View 。但是如果您想获得自定义行为(例如过滤),您可以自己构建 Collection View 并公开它而不是集合。

I don't want to load data every times when user change filter conditions, because the data volumne is very huge, the loading speed is very slow

如果可以的话,考虑在服务器端进行过滤。客户端过滤是在内存中执行的,可能会消耗大量系统资源。

更新

如果您想从过滤列表中选择多个国家/地区,可以将标量 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...
}

关于c# - 如何为集合设计多重过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34505787/

相关文章:

javascript - 尝试在 IHttpHandler 类中读取我的 http 调用的变量

c# - 等待带有动态参数的方法时抛出异常(有时)

c# - 创建 Type<SuperClass> 的通用列表并用派生类填充它的解决方法?

wpf - 如何使用ItemsControl分配<DataGrid.Columns>?

基于对象类型和子类型的 WPF DataGrid 动态列

javascript - 循环递归?

c# - 如何阻止我的 System.Messaging.MessageQueue 将我的字符串包装在 XML 中?

c# - 使用向导生成的 VS2010 WPF 项目未编译

c++ - 对于未排序的范围是否有等效的 std::includes ?

python - 从最后一个产生的对象而不是值中查找元素