过滤通用列表的最简单方法

时间:2011-03-21 13:34:14

标签: c# datagridview filter

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

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; }
}

我使用它作为WinForms应用程序中DataGridView的简单源代码,使用GUI中的“选择数据源”创建,这导致自动创建的类filterResultBindingSource

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

我怎样才能以最快/最简单的方式创建自定义列表,绑定源或第三种以支持过滤?从我所看到的,实现IBindingListView或新的BindingSource涉及很多工作,但如果我错了,请纠正我。

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

2 个答案:

答案 0 :(得分:8)

在sourceforge.net上查看BindingListView project。这个项目相当容易使用,下载包含有用的样本。

但是,对于快速且易于实现的解决方案,请查看呈现here的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();
    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;
        }
    }
}

答案 1 :(得分:5)

我认为使用通用List对象最简单的方法是将其转换为DataTable。

    public Form1( )
    {
        InitializeComponent( );

        List<Item> list = new List<Item>( );
        list.Add( new Item( 1, "ITEM 001" ) );
        list.Add( new Item( 2, "ITEM 002" ) );
        list.Add( new Item( 3, "ITEM 003" ) );
        list.Add( new Item( 4, "ITEM 004" ) );
        list.Add( new Item( 5, "ITEM 005" ) );
        list.Add( new Item( 6, "ITEM 006" ) );
        list.Add( new Item( 7, "ITEM 007" ) );
        list.Add( new Item( 100, "SW-RED" ) );
        list.Add( new Item( 101, "SW-BLUE" ) );
        list.Add( new Item( 102, "SW-GREEN" ) );
        list.Add( new Item( 103, "SW-BLACK" ) );
        list.Add( new Item( 104, "SW-WHITE" ) );

        // convert list to table
        DataTable dt = new DataTable( );
        dt = Convert.ToDataTable<Item>( list );
        DataView view = dt.AsDataView( );
        view.RowFilter = "ItemID < 100";

        comboBox1.DataSource = view;
        comboBox1.ValueMember = "ItemID";
        comboBox1.DisplayMember = "Description";
    }