将DataGridViewAutoFilter与Equin BindingListView一起使用

时间:2017-04-03 03:18:46

标签: c# datagridview bindinglist

我试图将DataGridViewAutoFilter与我的DataGridView一起使用,但为了做到这一点,我需要一个实现IBindingListView的数据源。为了做到这一点,我使用Equin.ApplicationFramework BindingListView,据我所知,它不支持字符串过滤器,因为它不断抛出异常:

  

'无法从字符串表达式设置过滤器。'

我猜测AutoFilter想要使用字符串表达式来过滤列表,但Equin的BindingListView并不支持该选项。

有谁知道如何让DataGridViewAutoFilter与List一起使用?

我的绑定列表定义如下:

BindingListView<ScoutingRecord> displayedData = new BindingListView<ScoutingRecord>(Current.data);

我按如下方式应用AutoFilter标头:

    private void dgvMain_BindingContextChanged(object sender, EventArgs e)
    {
        if (dgvMain.DataSource == null) return;

        foreach (DataGridViewColumn col in dgvMain.Columns)
        {
            col.HeaderCell = new DataGridViewAutoFilterColumnHeaderCell(col.HeaderCell);
        }
        dgvMain.AutoResizeColumns();
    }

ScoutingRecord类的定义如下:

   public class ScoutingRecord
    {
        public string TeamNumber { get; set; }
        public string MatchNumber { get; set; }
        public string Alliance { get; set; }
        public string Position { get; set; }
     }

我应该使用不同的BindingList实现吗?

1 个答案:

答案 0 :(得分:0)

我从来没有能够使Equin实现工作,但在做了一些研究并使用来自不同MSDN博客条目的大量示例之后,我能够创建支持过滤的AdvancedList类。目前,它一次只支持一个过滤器,但我正在努力使用多个过滤器扩展它。

然而,我很惊讶.NET中没有可用的标准实现。我的聚合AdvancedList类包含在下面。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Reflection;

namespace AdvancedList
{
    public class AdvancedList<T> : BindingList<T>, IBindingListView where T : class
    {
        private bool isSorted;
        private ListSortDirection sortDirection = ListSortDirection.Ascending;
        private PropertyDescriptor sortProperty;

        private string filterValue = null;
        private string filterPropertyNameValue;
        private Object filterCompareValue;

        private string[] filterPropertyNameValues;
        private Object[] filterCompareValues;

        List<T> unfilteredListValue = new List<T>();

        // Gets the property that indicates which property we're filtering against.
        public string FilterPropertyName
        {
            get { return filterPropertyNameValue; }
        }

        // Gets the property indicating the value we're comparing the property to.
        public Object FilterCompare
        {
            get { return filterCompareValue; }
        }

        // Create a blank instance of AdvancedList
        public AdvancedList()
        {
        }

        // Populate the list from a source list
        public AdvancedList(List<T> list) : base(list)
        {
        }

        // Gets the property that indicates if sorting is supported
        protected override bool SupportsSortingCore
        {
            get { return true; }
        }

        // Gets the property that indicates if the list is sorted
        protected override bool IsSortedCore
        {
            get { return isSorted; }
        }

        // Gets the proerty indicating the sort direction
        protected override ListSortDirection SortDirectionCore
        {
            get { return sortDirection; }
        }

        // Gets the property descriptor used for sorting the list
        protected override PropertyDescriptor SortPropertyCore
        {
            get { return sortProperty; }
        }

        // Removes any sorting applied
        protected override void RemoveSortCore()
        {
            sortDirection = ListSortDirection.Ascending;
            sortProperty = null;
            isSorted = false;
        }

        // Enables a sorting of the list
        protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
        {
            sortProperty = prop;
            sortDirection = direction;

            List<T> list = Items as List<T>;
            if (list == null) return;

            list.Sort(Compare);

            isSorted = true;
            //fire an event that the list has been changed.
            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        // Compare the values
        private int Compare(T lhs, T rhs)
        {
            var result = OnComparison(lhs, rhs);
            //invert if descending
            if (sortDirection == ListSortDirection.Descending)
                result = -result;
            return result;
        }

        // Handle different compare instances.
        private int OnComparison(T lhs, T rhs)
        {
            object lhsValue = lhs == null ? null : sortProperty.GetValue(lhs);
            object rhsValue = rhs == null ? null : sortProperty.GetValue(rhs);
            if (lhsValue == null)
            {
                return (rhsValue == null) ? 0 : -1; //nulls are equal
            }
            if (rhsValue == null)
            {
                return 1; //first has value, second doesn't
            }
            if (lhsValue is IComparable)
            {
                return ((IComparable)lhsValue).CompareTo(rhsValue);
            }
            if (lhsValue.Equals(rhsValue))
            {
                return 0; //both are the same
            }
            //not comparable, compare ToString
            return lhsValue.ToString().CompareTo(rhsValue.ToString());
        }

        public void ApplySort(ListSortDescriptionCollection sorts)
        {
            throw new NotImplementedException();
        }

        // Return true to indicate this class supports filtering
        public bool SupportsFiltering
        {
            get { return true; }
        }

        // Return the unfiltered list.
        public List<T> UnfilteredList
        {
            get { return unfilteredListValue; }
        }

        // Get and Set te filter string
        public string Filter
        {
            get
            {
                return filterValue;
            }

            set
            {
                if (filterValue != value)
                {
                    RaiseListChangedEvents = false;

                    // If filter value is null, reset list.
                    if (value == null)
                    {
                        this.ClearItems();

                        foreach (T t in unfilteredListValue)
                            this.Items.Add(t);

                        filterValue = value;
                    }

                    // If the value is empty string, do nothing.
                    else if (value == "") { }

                    // If the value is not null or string, than process normal.
                    // Regex.Matches(value, "[?[\\w]+]? ?[=] ?'?[\\w|/: ]+'?", RegexOptions.Singleline)
                    else if (Regex.Matches(value, "[?[\\w]+]? ?[=] ?'?[\\w]+'?", RegexOptions.Singleline).Count == 0)
                    {
                        // If the filter is not set.
                        unfilteredListValue.Clear();
                        unfilteredListValue.AddRange(this.Items);
                        filterValue = value;
                        GetFilterParts();
                        ApplyFilter();
                    }
                    // Regex.Matches(value, "[?[\\w]+]? ?[=] ?'?[\\w|/: ]+'?", RegexOptions.Singleline)
                    else if (Regex.Matches(value, "[?[\\w]+]? ?[=] ?'?[\\w]+'?", RegexOptions.Singleline).Count > 1)
                    {
                        unfilteredListValue.Clear();
                        unfilteredListValue.AddRange(this.Items);
                        filterValue = value;
                        GetFilterEntries();
                    }
                    else
                        throw new ArgumentException("Filter is not in the format: propName = 'value'.");

                    RaiseListChangedEvents = true;
                    OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
                }
            }
        }

        // If multiple filters were specified, separate the filter entries.
        // Incomplete: currently only handles AND. No handling of brackets, OR among others.
        public void GetFilterEntries()
        {
            string[] filterentries = Filter.Split(new string[] { "AND" }, StringSplitOptions.RemoveEmptyEntries);

            int index = 0;

            foreach (string filter in filterentries)
            {
                string[] filterParts = filter.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);

                filterPropertyNameValues[index] = filterParts[0].Replace("[", "").Replace("]", "").Trim();

                PropertyDescriptor propDesc = TypeDescriptor.GetProperties(typeof(T))[filterPropertyNameValues[0].ToString()];

                if (propDesc != null)
                {
                    try
                    {
                        TypeConverter converter = TypeDescriptor.GetConverter(propDesc.PropertyType);
                        filterCompareValues[index] = converter.ConvertFromString(filterParts[1].Replace("'", "").Trim());
                    }
                    catch (NotSupportedException)
                    {
                        throw new ArgumentException("Specified filter value " +
                          FilterCompare + " can not be converted from string. Implement a type converter for " + propDesc.PropertyType.ToString());
                    }
                }
                else throw new ArgumentException("Specified property '" + filterPropertyNameValues[0] + "' is not found on type " + typeof(T).Name + ".");
            }
        }

        // Parse the filter entry to it get the Property Name and Compare Value.
        public void GetFilterParts()

        {
            string[] filterParts = Filter.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);

            filterPropertyNameValue = filterParts[0].Replace("[", "").Replace("]", "").Trim();

            PropertyDescriptor propDesc = TypeDescriptor.GetProperties(typeof(T))[filterPropertyNameValue.ToString()];

            if (propDesc != null)
            {
                try
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(propDesc.PropertyType);
                    filterCompareValue = converter.ConvertFromString(filterParts[1].Replace("'", "").Trim());
                }
                catch (NotSupportedException)
                {
                    throw new ArgumentException("Specified filter value " +
                      FilterCompare + " can not be converted from string. Implement a type converter for " +propDesc.PropertyType.ToString()) ;
                }
            }
            else throw new ArgumentException("Specified property '" + FilterPropertyName + "' is not found on type " + typeof(T).Name + ".");
        }

        // Applies the filter to the list, returning only entries that match the filter.
        // Need a new version of this to handle multiple filters.
        private void ApplyFilter()
        {
            unfilteredListValue.Clear();
            unfilteredListValue.AddRange(this.Items);

            List<T> results = new List<T>();

            PropertyDescriptor propDesc = TypeDescriptor.GetProperties(typeof(T))[FilterPropertyName];

            if (propDesc != null)
            {
                int tempResults = -1;

                do
                {
                    tempResults = FindCore(tempResults + 1, propDesc, FilterCompare);

                    if (tempResults != -1)
                        results.Add(this[tempResults]);

                } while (tempResults != -1);
            }

            this.ClearItems();

            if (results != null && results.Count > 0)
            {
                foreach (T itemFound in results)
                    this.Add(itemFound);
            }
        }

        // Remove the filter.
        public void RemoveFilter()
        {
            if (Filter != null) Filter = null;
        }

        // Starts FindCore from startIndex 0 if no index was provided.
        protected override int FindCore(PropertyDescriptor prop, object key)
        {
            return FindCore(0, prop, key);
        }

        // Finds a List entry wher the Property value matches the compare value (key)
        protected int FindCore(int startIndex, PropertyDescriptor prop, object key)
        {
            // Get the property info for the specified property.
            PropertyInfo propInfo = typeof(T).GetProperty(prop.Name);

            T item;

            if (key != null)
            {
                // Loop through the items to see if the key value matches the property value.
                for (int i = startIndex; i < Count; ++i)
                {
                    item = (T)Items[i];
                    if (propInfo.GetValue(item, null).Equals(key))
                        return i;
                }
            }
            return -1;
        }

        // Required to implement IBindingListView, but not implemented here
        public ListSortDescriptionCollection SortDescriptions => throw new NotImplementedException();

        // Required to implement IBindingListView, but not implemented
        //public bool SupportsAdvancedSorting => throw new NotImplementedException();
        public bool SupportsAdvancedSorting
        {
            get { return false; }
        }

        // End of Class
    }

    // End of Namespace
}