实现排序,INotifyPropertyChanged,filter的BindingListView

由于将List<T>或者BindingList<T>绑定到BindingSource时,不支持BindingSource的排序和filter方法,特此扩展BindingListView<T>,再将BindingListView<T>绑定到BindingSource,可实现以上需求。

1.首先定义BusinessObjectBase类,实现INotifyPropertyChanged接口,可以做为实体类的基类。

public class BusinessObjectBase : INotifyPropertyChanged

    {

        #region INotifyPropertyChanged Members



        public event PropertyChangedEventHandler PropertyChanged;



        protected virtual void OnPropertyChanged(string propertyName)

        {

            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));

        }



        private void OnPropertyChanged(PropertyChangedEventArgs e)

        {

            if (null != PropertyChanged)

            {

                PropertyChanged(this, e);

            }

        }



        #endregion

    }

 

2.定义PropertyComparer<T>类,做为排序时的方法类。

public class PropertyComparer<T> : IComparer<T>

    {

        private ListSortDirection _direction;

        private PropertyDescriptor _property;



        public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)

        {

            _property = property;

            _direction = direction;

        }



        /// <summary>

        /// 比较方法

        /// </summary>

        /// <param name="x">相对属性x</param>

        /// <param name="y">相对属性y</param>

        /// <returns></returns>

        #region IComparer<T>



        public int Compare(T xWord, T yWord)

        {

            // Get property values

            object xValue = GetPropertyValue(xWord, _property.Name);

            object yValue = GetPropertyValue(yWord, _property.Name);



            // Determine sort order

            if (_direction == ListSortDirection.Ascending)

            {

                return CompareAscending(xValue, yValue);

            }

            return CompareDescending(xValue, yValue);

        }



        public bool Equals(T xWord, T yWord)

        {

            return xWord.Equals(yWord);

        }



        public int GetHashCode(T obj)

        {

            return obj.GetHashCode();

        }



        #endregion



        // Compare two property values of any type

        private int CompareAscending(object xValue, object yValue)

        {

            int result;



            // If values implement IComparer

            if (xValue is IComparable)

            {

                result = ((IComparable)xValue).CompareTo(yValue);

            }

            // If values don't implement IComparer but are equivalent

            else if (xValue == null || xValue.Equals(yValue))

            {

                result = 0;

            }

            // Values don't implement IComparer and are not equivalent, so compare as string values

            else result = xValue.ToString().CompareTo(yValue.ToString());



            // Return result

            return result;

        }



        private int CompareDescending(object xValue, object yValue)

        {

            // Return result adjusted for ascending or descending sort order ie

            // multiplied by 1 for ascending or -1 for descending

            return CompareAscending(xValue, yValue) * -1;

        }



        private object GetPropertyValue(T value, string property)

        {

            // Get property

            PropertyInfo propertyInfo = value.GetType().GetProperty(property);



            // Return value

            return propertyInfo.GetValue(value, null);

        }

    }

3.定义BindingListView<T>类,实现排序和过滤(Filter)

namespace BindingListViewTest

{

    public delegate void FilterHandler(object Sender, ref bool Include);



    [Serializable]

    public class BindingListView<T> : BindingList<T>, IBindingListView, ITypedList

    {

        private List<PropertyComparer<T>> comparers;

        private FilterHandler mFilterHandler;

        private string mFilterString = string.Empty;



        [NonSerialized]

        private PropertyDescriptorCollection properties;



        private ArrayList unfilteredItems = new ArrayList();



        public BindingListView()

        {

            // Get the 'shape' of the list. 

            // Only get the public properties marked with Browsable = true.

            PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(

                typeof(T),

                new Attribute[]

                    {

                        new BrowsableAttribute(true)

                    });



            // Sort the properties.

            properties = pdc.Sort();

        }



        public BindingListView(IList<T> list)

            : base(list)

        {

            // Get the 'shape' of the list. 

            // Only get the public properties marked with Browsable = true.

            PropertyDescriptorCollection pdc = TypeDescriptor.GetProperties(typeof(T),

                new Attribute[]

                    {

                        new BrowsableAttribute(true)

                    });



            // Sort the properties.

            properties = pdc.Sort();

        }



        #region Sorting



        private bool isSorted;

        private ListSortDirection sortDirection;

        private PropertyDescriptor sortProperty;



        protected override bool IsSortedCore

        {

            get { return isSorted; }

        }



        protected override bool SupportsSortingCore

        {

            get { return true; }

        }



        protected override ListSortDirection SortDirectionCore

        {

            get { return sortDirection; }

        }



        protected override PropertyDescriptor SortPropertyCore

        {

            get { return sortProperty; }

        }



        protected override void ApplySortCore(PropertyDescriptor property, ListSortDirection direction)

        {

            var items = Items as List<T>;



            if (items != null)

            {

                var pc = new PropertyComparer<T>(property, direction);

                items.Sort(pc);

                isSorted = true;

            }

            else

            {

                isSorted = false;

            }



            sortProperty = property;

            sortDirection = direction;



            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));

        }



        protected override void RemoveSortCore()

        {

            isSorted = false;

            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));

        }



        //public void Sort(PropertyDescriptor property, ListSortDirection direction)

        //{

        //    ApplySortCore(property, direction);

        //}



        #endregion



        #region Searching



        protected override bool SupportsSearchingCore

        {

            get { return true; }

        }



        protected override int FindCore(PropertyDescriptor property, object key)

        {

            // Specify search columns

            if (property == null) return -1;



            // Get list to search

            var items = Items as List<T>;

            // Traverse list for value

            if (items != null)

            {

                foreach (T item in items)

                {

                    // Test column search value

                    string value = property.GetValue(item).ToString();



                    // If value is the search value, return the 

                    // index of the data item

                    if (key.ToString() == value) return IndexOf(item);

                }

            }

            return -1;

        }



        #endregion



        #region IBindingListView 成员



        public void ApplySort(ListSortDescriptionCollection sorts)

        {

            // Get list to sort

            // Note: this.Items is a non-sortable ICollection<T>

            var items = Items as List<T>;



            // Apply and set the sort, if items to sort

            if (items != null)

            {

                SortDescriptions = sorts;

                comparers = new List<PropertyComparer<T>>();

                foreach (ListSortDescription sort in sorts)

                    comparers.Add(new PropertyComparer<T>(sort.PropertyDescriptor, sort.SortDirection));

                items.Sort(CompareValuesByProperties);

                //_isSorted = true;

            }



            OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));

        }



        public string Filter

        {

            get { return mFilterString; }

            set

            {

                bool Include = false;

                if (string.IsNullOrEmpty(mFilterString))

                {

                    unfilteredItems.AddRange((ICollection)Items);

                }

                Clear();

                foreach (T item in unfilteredItems)

                {

                    if (mFilterHandler != null)

                    {

                        Include = true;

                        mFilterHandler.Invoke(item, ref Include);

                        if (Include) Add(item);

                    }

                    else

                    {

                        Add(item);

                    }

                }

                mFilterString = value;

            }

        }



        public void RemoveFilter()

        {

            Clear();



            foreach (T item in unfilteredItems)

            {

                Add(item);

            }

            unfilteredItems.Clear();

        }



        public ListSortDescriptionCollection SortDescriptions { get; set; }



        public bool SupportsAdvancedSorting

        {

            get { return true; }

        }



        public bool SupportsFiltering

        {

            //get { return true; }

            get { return false; }

        }



        #endregion



        public FilterHandler FilterHandler

        {

            set

            {

                mFilterHandler = value;

                if (mFilterHandler == null)

                {

                    Filter = "";

                }

                else

                {

                    Filter = "any no zero length string";

                }

            }

        }



        private int CompareValuesByProperties(T x, T y)

        {

            if (x == null)

                return (y == null) ? 0 : -1;

            if (y == null)

                return 1;

            foreach (var comparer in comparers)

            {

                int retval = comparer.Compare(x, y);

                if (retval != 0)

                    return retval;

            }

            return 0;

        }



        #region ITypedList 成员



        public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)

        {

            PropertyDescriptorCollection pdc;



            if (null == listAccessors)

            {

                // Return properties in sort order.

                pdc = properties;

            }

            else

            {

                // Return child list shape.

                pdc = ListBindingHelper.GetListItemProperties(listAccessors[0].PropertyType);

            }



            return pdc;

        }



        // This method is only used in the design-time framework 

        // and by the obsolete DataGrid control.

        public string GetListName(PropertyDescriptor[] listAccessors)

        {

            return typeof(T).Name;

        }



        #endregion

    }

}

4.实现IEditableObject,INotifyPropertyChanged的测试实体类CategoryInfo

[Serializable]

    public class CategoryInfo : BusinessObjectBase, IEditableObject

    {

        private int _categoryid;

        private string _categoryname = string.Empty;

        private DateTime dt;

        private bool m_Editing; //是否处于编辑状态

        private CategoryInfo originalCategoryInfo;



        public int CategoryID

        {

            set

            {

                if (value != _categoryid)

                {

                    _categoryid = value;

                    OnPropertyChanged("CategoryID");

                }

            }

            get { return _categoryid; }

        }



        public string CategoryName

        {

            get { return _categoryname; }

            set

            {

                if (value==null||string.IsNullOrEmpty(value.Trim()))

                {

                    throw new ArgumentException("名称不能为空!");

                }

                if (value != _categoryname)

                {

                    _categoryname = value;

                    OnPropertyChanged("CategoryName");

                }

            }

        }



        public DateTime Dt

        {

            get { return dt; }

            set

            {

                if (value != dt)

                {

                    dt = value;

                    OnPropertyChanged("Dt");

                }

            }

        }



        public static BindingListView<CategoryInfo> GetCategory()

        {

            var list = new BindingListView<CategoryInfo>

                           {

                               new CategoryInfo

                                   {

                                       CategoryID = 1,

                                       CategoryName = "name1",

                                       Dt = DateTime.Now,

                                   },

                               new CategoryInfo

                                   {

                                       CategoryID = 2,

                                       CategoryName = "name2",

                                       Dt = DateTime.Now.AddDays(1),

                                   },

                           };

            return list;

        }



        #region IEditableObject 成员



        public void BeginEdit()

        {

            if (!m_Editing)

            {

                originalCategoryInfo = new CategoryInfo

                                           {

                                               CategoryID = CategoryID,

                                               CategoryName = CategoryName,

                                               Dt = Dt,

                                           };

                m_Editing = true;

            }

        }



        public void CancelEdit()

        {

            if (m_Editing)

            {

                CategoryID = originalCategoryInfo.CategoryID;

                CategoryName = originalCategoryInfo.CategoryName;

                Dt = originalCategoryInfo.Dt;

                m_Editing = false;

            }

        }



        public void EndEdit()

        {

            if (m_Editing)

            {

                originalCategoryInfo = new CategoryInfo();

                m_Editing = false;

            }

        }



        #endregion



    }

 

5.测试窗体实现关键代码:

BindingListView<CategoryInfo> list=CategoryInfo.GetCategory();

datagridview1.DataSource=categoryInfoBindingSource;

dataGridView1.AutoGenerateColumns = true;

categoryInfoBindingSource.DataSource = list;

textBox1.DataBindings.Add("Text", categoryInfoBindingSource, "CategoryID", true);

textBox2.DataBindings.Add("Text", categoryInfoBindingSource, "CategoryName", true);

dateTimePicker1.DataBindings.Add("Value", categoryInfoBindingSource, "Dt", true);

你可能感兴趣的:(ListView)