实现排序,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);

转载于:https://www.cnblogs.com/sqshine/archive/2009/05/23/1487924.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值