⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sortedcollectionbase.cs

📁 C# 版本的一个三层商业架构
💻 CS
字号:
using System;
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using CSLA.Resources;

/// <summary>
///
/// </summary>
namespace CSLA.Core
{
  /// <summary>
  /// This class implements sorting functionality for collections.
  /// </summary>
  /// <remarks>
  /// <para>
  /// This class inhirits from Core.BindableCollectionBase and adds
  /// sorting capability to collections. BusinessCollectionBase inherits
  /// from this class, and business collections should inherit from
  /// BusinessCollectionBase. Core.SortedCollectionBase is for internal
  /// framework use only.
  /// </para><para>
  /// The Core.BindableCollectionBase class implements the IBindableList
  /// interface. However, it doesn't actually implement sorting. Instead
  /// it delegates the sorting functionality to a set of protected virtual 
  /// methods. This class provides the actual sorting implementation
  /// by overriding those methods.
  /// </para>
  /// </remarks>
  [Serializable()]
  public class SortableCollectionBase : BindableCollectionBase
  {
    [NotUndoable()]
    private bool _isSorted = false;
    [NonSerialized()]
    [NotUndoable()]
    private PropertyDescriptor _sortProperty;
    [NotUndoable()]
    private string _sortPropertyName = string.Empty;
    [NotUndoable()]
    private ListSortDirection _listSortDirection = ListSortDirection.Ascending;
    [NotUndoable()]
    private ArrayList _unsortedList;
    [NotUndoable()]
    private bool _activelySorting = false;

    #region Properties

    /// <summary>
    /// Indicates whether the collection is in the process of
    /// being sorted at this time.
    /// </summary>
    protected bool ActivelySorting
    {
      get
      {
        return _activelySorting;
      }
    }

    /// <summary>
    /// Returns a value indicating whether the collection is currently
    /// sorted.
    /// </summary>
    protected override bool IBindingList_IsSorted
    {
      get
      {
        return _isSorted;
      }
    }

    /// <summary>
    /// Returns the property by which the collection is currently sorted.
    /// </summary>
    /// <remarks>
    /// This method is invoked via the IBindingList interface and is not
    /// intended for use by code in your business class.
    /// </remarks>
    protected override PropertyDescriptor IBindingList_SortProperty
    {
      get
      {
        if(_sortProperty == null && _sortPropertyName.Length > 0)
        {
          try
          {
            // we need to recreate the sortproperty value
            Type childType;
            if(List.Count > 0)
            {
              // get child type from the first element in the collection
              childType = List[0].GetType();
            }
            else
            {
              // get child type from Item property
              try
              {
                Type [] param = {typeof(int)};
                childType = this.GetType().GetProperty("Item", param).PropertyType;
              }
              catch
              {
                childType = typeof(object);
              }
            }

            // now get the property descriptor from the type
            _sortProperty = TypeDescriptor.GetProperties(childType)[_sortPropertyName];
          }
          catch
          {
            // we failed to recreate it - return nothing
            _sortProperty = null;
          }
        }
        return _sortProperty;
      }
    }

    /// <summary>
    /// Returns the current sort direction.
    /// </summary>
    /// <remarks>
    /// This method is invoked via the IBindingList interface and is not
    /// intended for use by code in your business class.
    /// </remarks>
    protected override ListSortDirection IBindingList_SortDirection
    {
      get
      {
        return _listSortDirection;
      }
    }

    #endregion

    #region ApplySort

    /// <summary>
    /// Structure to store temporary data for sorting.
    /// </summary>
    private struct SortData
    {
      private object _key;
      private object _value;

      public SortData(object key, object value)
      {
        _key = key;
        _value = value;
      }

      public object Value
      {
        get
        {
          return _value;
        }
      }

      public object Key
      {
        get
        {
          if(IsNumeric(_key) || _key is string)
            return _key;
          else
            return _key.ToString();
        }
      }
    }

    /// <summary>
    /// Contains code to compare SortData structures
    /// </summary>
    /// <remarks>
    /// This performs a case sensitive comparison. If you want a case insensitive
    /// comparison, change the code to use CaseInsensitiveComparer.Default instead.
    /// </remarks>
    private class SortDataCompare : IComparer
    {
      public int Compare(object x, object y)
      {
        SortData item1 = (SortData)x;
        SortData item2 = (SortData)y;

        return Comparer.Default.Compare(item1.Key, item2.Key);
      }
    }

    /// <summary>
    /// Applies a sort to the collection.
    /// </summary>
    /// <remarks>
    /// This method is invoked via the IBindingList interface and is not
    /// intended for use by code in your business class.
    /// </remarks>
    protected override void IBindingList_ApplySort(System.ComponentModel.PropertyDescriptor property, System.ComponentModel.ListSortDirection direction)
    {
      if(!AllowSort)
        throw new NotSupportedException(Strings.GetResourceString("SortingNotSupportedException"));

      _sortProperty = property;
      _sortPropertyName = _sortProperty.Name;
      _listSortDirection = direction;

      if(!_isSorted && List.Count > 0)
      {
        // this is our first time sorting so
        // make sure to store the original order
        _unsortedList = new ArrayList();
        foreach(object item in List)
          _unsortedList.Add(item);
      }

      if(List.Count > 1)
      {
        try
        {
          _activelySorting = true;

          // copy the key/value pairs into a sorted list
          ArrayList sortList = new ArrayList();
          for(int count = 0; count < List.Count; count++)
            sortList.Add(new SortData(CallByName(List[count], _sortPropertyName, CallType.Get), List[count]));
          sortList.Sort(new SortDataCompare());

          List.Clear();

          if(direction == ListSortDirection.Ascending)
          {
            foreach(SortData item in sortList)
              List.Add(item.Value);
          }
          else // direction = ListSortDirection.Descending
          {
            SortData item;
            for(int count = sortList.Count - 1; count >= 0; count--)
            {
              item = (SortData)sortList[count];
              List.Add(item.Value);
            }
          }

          _isSorted = true;
        }
        catch
        {
          IBindingList_RemoveSort();
        }
        finally
        {
          _activelySorting = false;
        }
      }
      else
        if(List.Count == 1)
        _isSorted = true;
    }

    #endregion

    #region Utils

    private static bool IsNumeric(object value)
    {
      double dbl;
      return double.TryParse(value.ToString(), System.Globalization.NumberStyles.Any, 
        System.Globalization.NumberFormatInfo.InvariantInfo, out dbl);
    }

    private enum CallType
    {
      Get,
      Let,
      Method,
      Set
    }

    private static object CallByName(object target, string methodName, CallType callType, params object [] args)
    {
      switch(callType)
      {
        case CallType.Get:
        {
          PropertyInfo p = target.GetType().GetProperty(methodName);
          return p.GetValue(target, args);
        }
        case CallType.Let:
        case CallType.Set:
        {
          PropertyInfo p = target.GetType().GetProperty(methodName);
          object [] index = null;
          args.CopyTo(index, 1);
          p.SetValue(target, args[0], index);
          return null;
        }
        case CallType.Method:
        {
          MethodInfo m = target.GetType().GetMethod(methodName);
          return m.Invoke(target, args);
        }
      }
      return null;
    }

    #endregion

    #region RemoveSort

    /// <summary>
    /// Removes any sort from the collection.
    /// </summary>
    /// <remarks>
    /// This method is invoked via the IBindingList interface and is not
    /// intended for use by code in your business class.
    /// </remarks>
    protected override void IBindingList_RemoveSort()
    {
      if(!AllowSort)
        throw new NotSupportedException(Strings.GetResourceString("SortingNotSupportedException"));

      if(_isSorted)
      {
        _activelySorting = true;

        //Return the list to its unsorted state
        List.Clear();

        foreach(object item in _unsortedList)
          List.Add(item);

        _unsortedList = null;

        _isSorted = false;
        _sortProperty = null;
        _sortPropertyName = string.Empty;
        _listSortDirection = ListSortDirection.Ascending;
        _activelySorting = false;
      }
    }

    #endregion

    #region Collection events

    /// <summary>
    /// Ensures that any sort is maintained as a new item is inserted.
    /// </summary>
    protected override void OnInsertComplete(int index, object value)
    {
      if(_isSorted && !ActivelySorting)
        _unsortedList.Add(value);
      base.OnInsertComplete(index, value);
    }

    /// <summary>
    /// Ensures that any sort is maintained as the list is cleared.
    /// </summary>
    protected override void OnClearComplete()
    {
      if(_isSorted && !ActivelySorting)
        _unsortedList.Clear();
      base.OnClearComplete();
    }

    /// <summary>
    /// Ensures that any sort is maintained as an item is removed.
    /// </summary>
    protected override void OnRemoveComplete(int index, object value)
    {
      if(_isSorted && !ActivelySorting)
        _unsortedList.Remove(value);
      base.OnRemoveComplete(index, value);
    }

    #endregion

    #region Search/Find

    /// <summary>
    /// Implements search/find functionality for the collection.
    /// </summary>
    protected override int IBindingList_Find(PropertyDescriptor property, object key)
    {
      if(!AllowFind)
        throw new NotSupportedException(Strings.GetResourceString("SearchingNotSupportedException"));

      object tmp;
      string prop = property.Name;

      for(int index = 0; index < List.Count; index++)
      {
        tmp = CallByName(List[index], prop, CallType.Get);
        if(tmp.Equals(key))
        {
          // we found a match
          return index;
        }
      }

      // we didn't find anything
      return -1;
    }

    #endregion

  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -