C# .net中PropertyDescriptor的使用和BindingList的ApplySort排序

找了好多资料都是java中PropertyDescriptor的使用,至于C#中的都抄袭别人的,又讲不清楚怎么用。官方文档也没不会手把手教你怎么用,经过一下午的研究,结果如下

1、找到PropertyDescriptor同一dll下的,使用TypeDescriptor反射出属性的PropertyDescriptorCollection ,从这里拿出对应属性的PropertyDescriptor

  var myAttribute = TypeDescriptor.GetProperties(_tbNumber)[nameof(_tbNumber.SerialNumber)];

  2、就可以使用ApplySort方法了

 ((IBindingList)listTable).ApplySort(myAttribute,ListSortDirection.Descending);

  但是

  但是

  但是

运行结果报错。也不知道微软是用PropertyDescriptor的哪个属性,我猜测过是使用了Descriptor特性,设置model中的Descriptor也无效。

 [Description(nameof(SerialNumber))]
 public int SerialNumber { get; set; }

 然后查询资料得知了重要的一点,BindList的属性SortPropertyCore默认不开启排序。需要派生类自行实现(我tm出口成小说“¥%……#@&@"省略一万字)

从网上找了实现代码,经过测试修改,如下(来自某论坛2008年的代码),麻烦帮忙艾特下微软把代码加进去

 public class MySortableBindingList<T> : BindingList<T>
 {
     // reference to the list provided at the time of instantiation
     List<T> originalList;
     ListSortDirection sortDirection;
     PropertyDescriptor sortProperty;
     // function that refereshes the contents
     // of the base classes collection of elements
     Action<MySortableBindingList<T>, List<T>>
                    populateBaseList = (a, b) => a.ResetItems(b);
     // a cache of functions that perform the sorting
     // for a given type, property, and sort direction
     static Dictionary<string, Func<List<T>, IEnumerable<T>>>
        cachedOrderByExpressions = new Dictionary<string, Func<List<T>,
                                                  IEnumerable<T>>>();
     public MySortableBindingList(){ originalList = new List<T>(); }

     public MySortableBindingList(IEnumerable<T> enumerable)
     {
         originalList = enumerable.ToList();
         populateBaseList(this, originalList);
     }
     public MySortableBindingList(List<T> list)
     {
         originalList = list;
         populateBaseList(this, originalList);
     }
     protected override void ApplySortCore(PropertyDescriptor prop,ListSortDirection direction)
     {
         /*
          Look for an appropriate sort method in the cache if not found .
          Call CreateOrderByMethod to create one. 
          Apply it to the original list.
          Notify any bound controls that the sort has been applied.
          */
         sortProperty = prop;
         sortDirection = direction;

         var orderByMethodName = sortDirection ==
             ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
         var cacheKey = typeof(T).GUID + prop.Name + orderByMethodName;

         if (!cachedOrderByExpressions.ContainsKey(cacheKey))
         {
             CreateOrderByMethod(prop, orderByMethodName, cacheKey);
         }
         ResetItems(cachedOrderByExpressions[cacheKey](originalList).ToList());
         ResetBindings();
     }
     private void CreateOrderByMethod(PropertyDescriptor prop,
                  string orderByMethodName, string cacheKey)
     {
         /*
          Create a generic method implementation for IEnumerable<T>.
          Cache it.
         */
         var sourceParameter = Expression.Parameter(typeof(List<T>), "source");
         var lambdaParameter = Expression.Parameter(typeof(T), "lambdaParameter");
         var accesedMember = typeof(T).GetProperty(prop.Name);
         var propertySelectorLambda =
             Expression.Lambda(Expression.MakeMemberAccess(lambdaParameter,
                               accesedMember), lambdaParameter);
         var orderByMethod = typeof(Enumerable).GetMethods()
                                       .Where(a => a.Name == orderByMethodName &&a.GetParameters().Length == 2)
                                       .Single()
                                       .MakeGenericMethod(typeof(T), prop.PropertyType);

         var orderByExpression = Expression.Lambda<Func<List<T>, IEnumerable<T>>>(
                                     Expression.Call(orderByMethod,
                                             new Expression[] { sourceParameter,
                                                            propertySelectorLambda }),
                                             sourceParameter);

         cachedOrderByExpressions.Add(cacheKey, orderByExpression.Compile());
     }

     protected override void RemoveSortCore()=> ResetItems(originalList);
     private void ResetItems(List<T> items)
     {
         base.ClearItems();
         for (int i = 0; i < items.Count; i++)
         {
             base.InsertItem(i, items[i]);
         }
     }

     protected override bool SupportsSortingCore => true;
     protected override ListSortDirection SortDirectionCore => sortDirection;

     protected override PropertyDescriptor SortPropertyCore => sortProperty;

     protected override void OnListChanged(ListChangedEventArgs e)
     {
         originalList = base.Items.ToList();
         base.OnListChanged(e);
     }
 }

 使用

MySortableBindingList<tbNumber> listTable = new MySortableBindingList<tbNumber>();
     private void Main_Load(object sender, EventArgs e)
     {
         dgv.DataSource = listTable;
     }
  private bool? added(tbNumber _tbNumber)
  {
      if (listTable.Count > 20)
      {
          TipCommon.ShowInfoTip("A maximum of 20 can be added");
          return false;
      }
      int c = listTable.Count(a => a.SerialNumber == _tbNumber.SerialNumber);
      if (c > 0)
      {
          TipCommon.ShowInfoTip("This serial number already exists.");
          return false;
      }
      listTable.Add(_tbNumber);


      var myAttribute = TypeDescriptor.GetProperties(_tbNumber)[nameof(_tbNumber.SerialNumber)];

      ((IBindingList)listTable).ApplySort(myAttribute,ListSortDirection.Descending);
      return true;
  }
   private void btnAdd_Click(object sender, EventArgs e)
   {
       frmNumberForm _frmNumberForm = new frmNumberForm();
       _frmNumberForm.added += added;
       _frmNumberForm.ShowDialog();
   }

 作者:兮去博客
出处:https://www.cnblogs.com/bklsj/p/17973010
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任

posted @ 2024-01-18 17:48  兮去  阅读(182)  评论(0编辑  收藏  举报