最简单的过滤通用列表的方法 [英] Simplest way to filter generic list

查看:168
本文介绍了最简单的过滤通用列表的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下类定义了我的表中的一个条目(我已经删除了brewity的构造函数,它简单地设置数据):

  class FilterResult 
{
public bool Checked {get;组; }
public string Url {get; private set;}
public string说明{get;私人集合}
public int ItemID {get;私人集合
}

我正在使用它作为WinForms应用程序中DataGridView的简单来源,使用GUI中的选择数据源创建,导致自动创建的类名为 filterResultBindingSource



现在,这种方法不支持DataGridView.Filter属性,我需要对结果进行简单的过滤。



我如何在最快/最简单的方法可能,创建自定义列表,绑定源或第三个来支持过滤?从我所看到的,有很多工作涉及实施IBindingListView或一个新的BindingSource,但如果我错了,请纠正我。



它不一定有要使用Filter属性,实际上可能会更容易,如果我可以实现一个自定义的方法,我可以使用列表中的 Where -method进行过滤。

解决方案

查看 BindingListView项目在sourceforge.net。这个项目很容易使用,下载包含有用的示例。



然而,为了快速,轻松地实现解决方案,请查看BindListView类(与sourceforge无关项目)提交了这里(具体列出9.7)。这是一个通用类,您可以将其设置为BindingSource的DataSource,并通过BindingSource的Filter属性过滤。对于我所链接的文章中讨论的如何使用它有一些限制,但对于我来说,这是您正在寻找的快速解决方案的完美选择。



我'添加,您可以使用这两种解决方案来允许在您的DGV中排序。



编辑:
我曾经获得的链接几年前的BindingListView类已经死了,所以我发现它在别的地方。我决定继续下面的代码,以备将来参考,以防此链接也消失。

  public class BindingListView< T> :BindingList< T>,IBindingListView,IRaiseItemChangedEvents 
{
private bool m_Sorted = false;
private bool m_Filtered = false;
private string m_FilterString = null;
private ListSortDirection m_SortDirection = ListSortDirection.Ascending;
private PropertyDescriptor m_SortProperty = null;
private ListSortDescriptionCollection m_SortDescriptions = new ListSortDescriptionCollection();
私人列表< T> m_OriginalCollection = new List< T>();

public BindingListView()
:base(){
}

public BindingListView(List< T> list)
:base列表){
}

protected override bool SupportsSearchingCore {
get {return true; }
}

protected override int FindCore(PropertyDescriptor属性,
对象键){
//简单迭代:
for(int i = 0; i< Count; i ++){
T item = this [i];
if(property.GetValue(item).Equals(key)){
return i;
}
}
return -1; // Not found

//替代搜索实现
//使用List.FindIndex:
//谓词< T> pred = delegate(T item)
// {
// if(property.GetValue(item).Equals(key))
// return true;
// else
// return false;
//};
//列表< T> list =作为列表的项目< T>;
// if(list == null)
// return -1;
// return list.FindIndex(pred);
}

protected override bool SupportsSortingCore {
get {return true; }
}
protected override bool IsSortedCore {
get {return m_Sorted; }
}

protected override ListSortDirection SortDirectionCore {
get {return m_SortDirection; }
}

protected override PropertyDescriptor SortPropertyCore {
get {return m_SortProperty; }
}

protected override void ApplySortCore(PropertyDescriptor属性,
ListSortDirection direction){
m_SortDirection = direction;
m_SortProperty = property;
SortComparer< T> comparer = new SortComparer< T>(property,direction);
ApplySortInternal(comparer);
}

private void ApplySortInternal(SortComparer< T> comparer){
if(m_OriginalCollection.Count == 0){
m_OriginalCollection.AddRange(this);
}
列表< T> listRef = this.Items为List< T>;
if(listRef == null)
return;
listRef.Sort(comparer);
m_Sorted = true;
OnListChanged(new ListChangedEventArgs(
ListChangedType.Reset,-1));
}

protected override void RemoveSortCore(){
if(!m_Sorted)
return;明确();
foreach(T item in m_OriginalCollection){
Add(item);
}
m_OriginalCollection.Clear();
m_SortProperty = null;
m_SortDescriptions = null;
m_Sorted = false;
}

void IBindingListView.ApplySort(ListSortDescriptionCollection sort){
m_SortProperty = null;
m_SortDescriptions =排序;
SortComparer< T> comparer = new SortComparer< T>(排序);
ApplySortInternal(comparer);
}

string IBindingListView.Filter {
get {
return m_FilterString;
}
set {
m_FilterString = value;
m_Filtered = true;
UpdateFilter();
}
}

void IBindingListView.RemoveFilter(){
if(!m_Filtered)
return;
m_FilterString = null;
m_Filtered = false;
m_Sorted = false;
m_SortDescriptions = null;
m_SortProperty = null;
Clear();
foreach(T item in m_OriginalCollection){
Add(item);
}
m_OriginalCollection.Clear();
}
ListSortDescriptionCollection IBindingListView.SortDescriptions {
get {
return m_SortDescriptions;
}
}

bool IBindingListView.SupportsAdvancedSorting {
get {
return true;
}
}

bool IBindingListView.SupportsFiltering {
get {
return true;
}
}

protected virtual void UpdateFilter(){
int equalsPos = m_FilterString.IndexOf('=');
//获取属性名称
string propName = m_FilterString.Substring(0,equalsPos).Trim();
//获取过滤条件
string criteria = m_FilterString.Substring(equalsPos + 1,
m_FilterString.Length - equalsPos - 1).Trim();
//带引号和尾随引号
criteria = criteria.Substring(1,criteria.Length - 2);
//获取过滤器属性的属性描述符
PropertyDescriptor propDesc = TypeDescriptor.GetProperties(typeof(T))[propName];
if(m_OriginalCollection.Count == 0){
m_OriginalCollection.AddRange(this);
}
列表< T> currentCollection = new List< T>(this);
Clear();
foreach(currentCollection中的T项){
对象值= propDesc.GetValue(item);
if(value.ToString()== criteria){
Add(item);
}
}
}

bool IBindingList.AllowNew {
get {
return CheckReadOnly();
}
}

bool IBindingList.AllowRemove {
get {
return CheckReadOnly();
}
}

private bool CheckReadOnly(){
if(m_Sorted || m_Filtered){
return false;
} else {
return true;
}
}

protected override void InsertItem(int index,T item){
foreach(PropertyDescriptor propDesc in
TypeDescriptor.GetProperties(item)) {
if(propDesc.SupportsChangeEvents){
propDesc.AddValueChanged(item,OnItemChanged);
}
}
base.InsertItem(index,item);
}

protected override void RemoveItem(int index){
T item = Items [index];
PropertyDescriptorCollection propDescs = TypeDescriptor.GetProperties(item);
foreach(propDescs中的PropertyDescriptor propDesc){
if(propDesc.SupportsChangeEvents){
propDesc.RemoveValueChanged(item,OnItemChanged);
}
}
base.RemoveItem(index);
}

void OnItemChanged(object sender,EventArgs args){
int index = Items.IndexOf((T)sender);
OnListChanged(new ListChangedEventArgs(
ListChangedType.ItemChanged,index));
}

bool IRaiseItemChangedEvents.RaisesItemChangedEvents {
get {return true; }
}
}

class SortComparer< T> :IComparer< T>
{
private ListSortDescriptionCollection m_SortCollection = null;
private PropertyDescriptor m_PropDesc = null;
private ListSortDirection m_Direction =
ListSortDirection.Ascending;

public SortComparer(PropertyDescriptor propDesc,
ListSortDirection direction){
m_PropDesc = propDesc;
m_Direction = direction;
}

public SortComparer(ListSortDescriptionCollection sortCollection){
m_SortCollection = sortCollection;
}

int IComparer< T> .Compare(T x,T y){
if(m_PropDesc!= null)//简单排序
{
object xValue = m_PropDesc.GetValue(x);
对象yValue = m_PropDesc.GetValue(y);
返回CompareValues(xValue,yValue,m_Direction);
} else if(m_SortCollection!= null&&
m_SortCollection.Count> 0){
return RecursiveCompareInternal(x,y,0);
} else return 0;
}

private int CompareValues(object xValue,object yValue,
ListSortDirection direction){

int retValue = 0;
if(xValue is IComparable){
retValue =((IComparable)xValue).CompareTo(yValue);
} else if(yValue is IComparable){
retValue =((IComparable)yValue).CompareTo(xValue);
}
//不可比较,比较String表示
else if(!xValue.Equals(yValue)){
retValue = xValue.ToString()CompareTo(yValue.ToString ());
}
if(direction == ListSortDirection.Ascending){
return retValue;
} else {
return retValue * -1;
}
}

private int RecursiveCompareInternal(T x,T y,int index){
if(index> = m_SortCollection.Count)
返回0; //终止条件

ListSortDescription listSortDesc = m_SortCollection [index];
object xValue = listSortDesc.PropertyDescriptor.GetValue(x);
对象yValue = listSortDesc.PropertyDescriptor.GetValue(y);

int retValue = CompareValues(xValue,
yValue,listSortDesc.SortDirection);
if(retValue == 0){
return RecursiveCompareInternal(x,y,++ index);
} else {
return retValue;
}
}
}


I have the following class that defines an entry in my table (I have remove the constructor for brewity, it simple sets that data):

class FilterResult
{
    public bool Checked { get; set; }
    public string Url { get; private set;}
    public string Description { get; private set; }
    public int ItemID { get; private set; }
}

I am using this as a simple source for a DataGridView in a WinForms application, created using the 'Choose Data Source' in the GUI, which resulted in a automatically created class called filterResultBindingSource.

Now, this approach does not support the DataGridView.Filter property, and I need to be able to do a simple filter on the results.

How can I, in the fastest/easiest way possible, create a custom list, binding source or something third to support filtering? From what I've seen, there's a lot of work involved in implementing IBindingListView or a new BindingSource, but correct me if I'm wrong.

It does not necessarily have to use the Filter property, in fact it would probably be easier if I could implement a custom method where I can filter using the Where-method available on the list.

解决方案

Check out the BindingListView project over at sourceforge.net. This project is fairly easy to use and the download includes useful samples.

However, for your fast and easy to implement solution look at the BindListView class (no relation to the sourceforge project) presented here (specifically listing 9.7). This is a generic class that you can set as your BindingSource's DataSource and filter through the BindingSource's Filter property. There are some restrictions on how you can use it that are discussed in the article I linked but for me it's been perfect for the quick solution you're looking for.

I'll add that you can use both solutions to allow sorting in your DGV.

EDIT: The link I used to get the BindingListView class a couple years ago was dead so I found it somewhere else. I decided to go ahead and post the code below for future reference in case this link also disappears.

public class BindingListView<T> : BindingList<T>, IBindingListView, IRaiseItemChangedEvents
{
    private bool m_Sorted = false;
    private bool m_Filtered = false;
    private string m_FilterString = null;
    private ListSortDirection m_SortDirection = ListSortDirection.Ascending;
    private PropertyDescriptor m_SortProperty = null;
    private ListSortDescriptionCollection m_SortDescriptions = new ListSortDescriptionCollection();
    private List<T> m_OriginalCollection = new List<T>();

    public BindingListView()
        : base() {
    }

    public BindingListView(List<T> list)
        : base(list) {
    }

    protected override bool SupportsSearchingCore {
        get { return true; }
    }

    protected override int FindCore(PropertyDescriptor property,
    object key) {
        // Simple iteration:
        for (int i = 0; i < Count; i++) {
            T item = this[i];
            if (property.GetValue(item).Equals(key)) {
                return i;
            }
        }
        return -1; // Not found

        // Alternative search implementation
        // using List.FindIndex:
        //Predicate<T> pred = delegate(T item)
        //{
        // if (property.GetValue(item).Equals(key))
        // return true;
        // else
        // return false;
        //};
        //List<T> list = Items as List<T>;
        //if (list == null)
        // return -1;
        //return list.FindIndex(pred);
    }

    protected override bool SupportsSortingCore {
        get { return true; }
    }
    protected override bool IsSortedCore {
        get { return m_Sorted; }
    }

    protected override ListSortDirection SortDirectionCore {
        get { return m_SortDirection; }
    }

    protected override PropertyDescriptor SortPropertyCore {
        get { return m_SortProperty; }
    }

    protected override void ApplySortCore(PropertyDescriptor property,
      ListSortDirection direction) {
        m_SortDirection = direction;
        m_SortProperty = property;
        SortComparer<T> comparer = new SortComparer<T>(property, direction);
        ApplySortInternal(comparer);
    }

    private void ApplySortInternal(SortComparer<T> comparer) {
        if (m_OriginalCollection.Count == 0) {
            m_OriginalCollection.AddRange(this);
        }
        List<T> listRef = this.Items as List<T>;
        if (listRef == null)
            return;
        listRef.Sort(comparer);
        m_Sorted = true;
        OnListChanged(new ListChangedEventArgs(
          ListChangedType.Reset, -1));
    }

    protected override void RemoveSortCore() {
        if (!m_Sorted)
            return; Clear();
        foreach (T item in m_OriginalCollection) {
            Add(item);
        }
        m_OriginalCollection.Clear();
        m_SortProperty = null;
        m_SortDescriptions = null;
        m_Sorted = false;
    }

    void IBindingListView.ApplySort(ListSortDescriptionCollection sorts) {
        m_SortProperty = null;
        m_SortDescriptions = sorts;
        SortComparer<T> comparer = new SortComparer<T>(sorts);
        ApplySortInternal(comparer);
    }

    string IBindingListView.Filter {
        get {
            return m_FilterString;
        }
        set {
            m_FilterString = value;
            m_Filtered = true;
            UpdateFilter();
        }
    }

    void IBindingListView.RemoveFilter() {
        if (!m_Filtered)
            return;
        m_FilterString = null;
        m_Filtered = false;
        m_Sorted = false;
        m_SortDescriptions = null;
        m_SortProperty = null;
        Clear();
        foreach (T item in m_OriginalCollection) {
            Add(item);
        }
        m_OriginalCollection.Clear();
    }
    ListSortDescriptionCollection IBindingListView.SortDescriptions {
        get {
            return m_SortDescriptions;
        }
    }

    bool IBindingListView.SupportsAdvancedSorting {
        get {
            return true;
        }
    }

    bool IBindingListView.SupportsFiltering {
        get {
            return true;
        }
    }

    protected virtual void UpdateFilter() {
        int equalsPos = m_FilterString.IndexOf('=');
        // Get property name
        string propName = m_FilterString.Substring(0, equalsPos).Trim();
        // Get filter criteria
        string criteria = m_FilterString.Substring(equalsPos + 1,
           m_FilterString.Length - equalsPos - 1).Trim();
        // Strip leading and trailing quotes
        criteria = criteria.Substring(1, criteria.Length - 2);
        // Get a property descriptor for the filter property
        PropertyDescriptor propDesc = TypeDescriptor.GetProperties(typeof(T))[propName];
        if (m_OriginalCollection.Count == 0) {
            m_OriginalCollection.AddRange(this);
        }
        List<T> currentCollection = new List<T>(this);
        Clear();
        foreach (T item in currentCollection) {
            object value = propDesc.GetValue(item);
            if (value.ToString() == criteria) {
                Add(item);
            }
        }
    }

    bool IBindingList.AllowNew {
        get {
            return CheckReadOnly();
        }
    }

    bool IBindingList.AllowRemove {
        get {
            return CheckReadOnly();
        }
    }

    private bool CheckReadOnly() {
        if (m_Sorted || m_Filtered) {
            return false;
        } else {
            return true;
        }
    }

    protected override void InsertItem(int index, T item) {
        foreach (PropertyDescriptor propDesc in
           TypeDescriptor.GetProperties(item)) {
            if (propDesc.SupportsChangeEvents) {
                propDesc.AddValueChanged(item, OnItemChanged);
            }
        }
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index) {
        T item = Items[index];
        PropertyDescriptorCollection propDescs = TypeDescriptor.GetProperties(item);
        foreach (PropertyDescriptor propDesc in propDescs) {
            if (propDesc.SupportsChangeEvents) {
                propDesc.RemoveValueChanged(item, OnItemChanged);
            }
        }
        base.RemoveItem(index);
    }

    void OnItemChanged(object sender, EventArgs args) {
        int index = Items.IndexOf((T)sender);
        OnListChanged(new ListChangedEventArgs(
          ListChangedType.ItemChanged, index));
    }

    bool IRaiseItemChangedEvents.RaisesItemChangedEvents {
        get { return true; }
    }
}

class SortComparer<T> : IComparer<T>
{
    private ListSortDescriptionCollection m_SortCollection = null;
    private PropertyDescriptor m_PropDesc = null;
    private ListSortDirection m_Direction =
       ListSortDirection.Ascending;

    public SortComparer(PropertyDescriptor propDesc,
       ListSortDirection direction) {
        m_PropDesc = propDesc;
        m_Direction = direction;
    }

    public SortComparer(ListSortDescriptionCollection sortCollection) {
        m_SortCollection = sortCollection;
    }

    int IComparer<T>.Compare(T x, T y) {
        if (m_PropDesc != null) // Simple sort
  {
            object xValue = m_PropDesc.GetValue(x);
            object yValue = m_PropDesc.GetValue(y);
            return CompareValues(xValue, yValue, m_Direction);
        } else if (m_SortCollection != null &&
            m_SortCollection.Count > 0) {
            return RecursiveCompareInternal(x, y, 0);
        } else return 0;
    }

    private int CompareValues(object xValue, object yValue,
       ListSortDirection direction) {

        int retValue = 0;
        if (xValue is IComparable) {
            retValue = ((IComparable)xValue).CompareTo(yValue);
        } else if (yValue is IComparable) {
            retValue = ((IComparable)yValue).CompareTo(xValue);
        }
            // not comparable, compare String representations
        else if (!xValue.Equals(yValue)) {
            retValue = xValue.ToString().CompareTo(yValue.ToString());
        }
        if (direction == ListSortDirection.Ascending) {
            return retValue;
        } else {
            return retValue * -1;
        }
    }

    private int RecursiveCompareInternal(T x, T y, int index) {
        if (index >= m_SortCollection.Count)
            return 0; // termination condition

        ListSortDescription listSortDesc = m_SortCollection[index];
        object xValue = listSortDesc.PropertyDescriptor.GetValue(x);
        object yValue = listSortDesc.PropertyDescriptor.GetValue(y);

        int retValue = CompareValues(xValue,
           yValue, listSortDesc.SortDirection);
        if (retValue == 0) {
            return RecursiveCompareInternal(x, y, ++index);
        } else {
            return retValue;
        }
    }
}

这篇关于最简单的过滤通用列表的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆