2011-03-21 31 views
1

我有以下的类定义在我的表中的条目(我已经删除了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的简单源代码,这导致了一个名为filterResultBindingSource的自动创建的类。

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

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

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

回答

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"; 
    } 
+0

Thx,转换为DataView对我来说是一个简单的方法(但有点慢) – 2013-06-11 10:44:26

+0

Convert.ToDataTable从哪里来? – chrispepper1989 2015-08-11 10:53:13

8

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

但是,为了您的快速和易于实施的解决方案看看here(特别是列表9.7)呈现的BindListView类(与sourceforge项目无关)。这是一个通用类,您可以将其设置为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; 
     } 
    } 
} 
+0

FWIW,BindingListView在2013年被分为github。[waynebloss/BindingListView](https://github.com/waynebloss/BindingListView) – bvj 2015-09-24 01:24:11