none
BindingList<T>作为BindingSource的数据源,如何实现bindingSource的Filter筛选 RRS feed

  • 问题

  • 如题,以前bindingSource绑定DataTable,什么排序啊筛选啊,都没问题。现在研究实体类了,客户端还是用bindingsource,只是要绑定BindingList<T>,排序有关的,网上看到不少,可如何筛选呢?

    不想用BindingList的where过滤再ToList再重新设置bindingSource的Datasource方式,感觉这样做不是正确方法?而且如果再改为DataTable,不是统一的filter了。

    想问,如何给BindingList<T>增添功能,使之可以通过BindingSource的Filter=“xxxx”就能筛选呢?

    谢谢!


    陈锦巍

    2019年5月22日 8:38

全部回复

  • Hi 陈锦巍,

    只有实现IBindingListView接口的底层列表才支持过滤。而从官方文档中可以发现BindingList<T>并未实现该接口。所以BindingList<T>是无法实现过滤的。

    Regards,

    Kyle


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年5月23日 5:50
  • 是的,我查的资料也是说要实现IBindingListView接口,那该怎样实现呢?我找了段实现接口的代码,可是筛选还是不行啊,想问如何筛选呢?

    看了一些代码,筛选都是清空列表,然后将符合条件的添加进去。这速度,如果记录很多,肯定会很慢的。

    而且这样做,选一次,List里的内容就只有符合前次筛选条件的了,再进行筛选,只会在上次筛选结果中再次筛选。

    如果想保留原始表,那就得在初始化集合时弄一个原始列表作为备份,一旦当前list有任何添加、删除,都得将备份表对应着添加、删除才行。那这样如果有几万条数据,该会多慢啊?

    难怪我看的有关代码不是实时筛选,而是输入框输入完毕,点Apply开始筛选呢。如果是写在文本框Changed事件里,那这种方式的性能肯定不高吧。只有这样实现吗?


    陈锦巍


    2019年5月23日 13:21
  • Hi 陈锦巍,

    要对List进行筛选操作唯一可行的方法就是使用“.Where()”方法,使用Linq来提高执行效率。

    Regards,

    Kyle


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年5月27日 6:53
  • 嗯,对list筛选用使用“.Where()”方法我知道,但是,如主题,我是想实现一个BindingListview,使得筛选时都可以用bindingSource.Filter="key=xxx",这种与绑定打他table一样统一的方式来筛选数据。

    但是在我的实现类里面,好像不能调用.Where方法。而且,似乎即使是调用.Where方法,返回的是IEnumerable类型的,还是要清除当前列表,再将得到的查询结果一一添加到当前列表才行。这样实现吗?如果这样,千百条数据还行,要是上万乃至几十万条数据,速度肯定会很慢啊。贴点代码:

    public class BindingListView<T> : BindingList<T>, IBindingListView
        {
            public BindingListView()
            { }
            public BindingListView(IList<T> list) : base(list)
            {
                foreach (var item in list)
                {
                    this.originalList.Add(item);
                }
            }
            bool isSortedValue;
    .
    .
    .
            internal IEnumerable<T> ApplyFilter(SingleFilterInfo filterParts)
            {
                
              foreach (T item in this.originalList)
                {
                    if (filterParts.PropDesc.GetValue(item) != null)
                    {
                        IComparable compareValue =
                            filterParts.PropDesc.GetValue(item) as IComparable;
                        int result =
                            compareValue.CompareTo(filterParts.CompareValue);
                        if (filterParts.OperatorValue ==
                            FilterOperator.EqualTo && result == 0)
                            yield return item;
                        if (filterParts.OperatorValue ==
                            FilterOperator.GreaterThan && result > 0)
                            yield return item;
                        if (filterParts.OperatorValue ==
                            FilterOperator.LessThan && result < 0)
                            yield return item;
                    }
                }
            }
    
            public string Filter
            {
                get => filterValue;
                set
                {
                    RaiseListChangedEvents = false;
    
                    // 如果为空则重置列表
                    if (string.IsNullOrEmpty(value))
                        ResetList();
                    else
                    {
                        int count = 0;
                        string[] matches = value.Split(new string[] { " AND " },
                            StringSplitOptions.RemoveEmptyEntries);
                        while (count < matches.Length)
                        {
                            string filterPart = matches[count].ToString();
                            SingleFilterInfo filterInfo = ParseFilter(filterPart);
                            this.Items.Clear();
                            var seq = ApplyFilter(filterInfo);
                           foreach (var I in seq)
                            {
                                this.Items.Add(I);
                            }                     
                            count++;
                        }
                    }
                    // Set the filter value and turn on list changed events.
                    filterValue = value;
                    RaiseListChangedEvents = true;
                    OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
                }
    
            }
    




    陈锦巍

    2019年5月28日 11:12
  • Hi 陈锦巍,

    我这里找到了一个实现了“IBindingListView”的Nuget包,你可以参考一下。

    BindingListView

    Equin.ApplicationFramework.BindingListView

    Regards,

    Kyle


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2019年5月29日 5:39
  • 嗯嗯,看过了,但这个类似乎还不完善,比如不能筛选

    bindingSource1.Filter = $"Description like '{txtDesc.Text}%'";

    这样的条件。

    自己写了个BindingListView,实现了。只是,不管怎样,我想如果用List<T>作为数据源的话,那筛选其实都是清空list,再从备份表中查询出符合条件的Add到List<T>中吧。没有真正意义上的过滤(只显示符合条件的)。那这样的话,一旦有筛选操作,数据量大了必然性能很差。我试过,上万条数据,用DataTable排序筛选都很快反应的,而用bindingListview作为数据源,设置

    bindingSource1.Filter = $"Description like '{txtDesc.Text}%'";

    筛选会很慢才展示出来。

    那Datatable的筛选,该不会也是同样实现的吧(清空,用符合条件的填充)。但DataTable确实很快。以后的开发中,如果数据量大,又牵扯排序与筛选的话,还是用DataTable吧。是不是这样?


    陈锦巍

    2019年5月29日 15:07
  • DataTable对关键字字段做了索引的,非关键字搜索还是比较慢。具体实现可以去看源代码。


    Visual C++ MVP

    2019年5月30日 16:17
    版主