This commit is contained in:
341
source/csla10/CSLA/SortedCollectionBase.vb
Normal file
341
source/csla10/CSLA/SortedCollectionBase.vb
Normal file
@@ -0,0 +1,341 @@
|
||||
Imports System.ComponentModel
|
||||
|
||||
''' <summary>
|
||||
'''
|
||||
''' </summary>
|
||||
Namespace 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
|
||||
Inherits BindableCollectionBase
|
||||
|
||||
<NotUndoable()> _
|
||||
Private mIsSorted As Boolean = False
|
||||
<NonSerialized(), NotUndoable()> _
|
||||
Private mSortProperty As PropertyDescriptor
|
||||
<NotUndoable()> _
|
||||
Private mSortPropertyName As String
|
||||
<NotUndoable()> _
|
||||
Private mListSortDirection As ListSortDirection = ListSortDirection.Ascending
|
||||
<NotUndoable()> _
|
||||
Private mUnsortedList As ArrayList
|
||||
<NotUndoable()> _
|
||||
Private mActivelySorting As Boolean = False
|
||||
|
||||
#Region " Properties "
|
||||
|
||||
''' <summary>
|
||||
''' Indicates whether the collection is in the process of
|
||||
''' being sorted at this time.
|
||||
''' </summary>
|
||||
Protected ReadOnly Property ActivelySorting() As Boolean
|
||||
Get
|
||||
Return mActivelySorting
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <summary>
|
||||
''' Returns a value indicating whether the collection is currently
|
||||
''' sorted.
|
||||
''' </summary>
|
||||
Protected Overrides ReadOnly Property IBindingList_IsSorted() As Boolean
|
||||
Get
|
||||
Return mIsSorted
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <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 Overrides ReadOnly Property IBindingList_SortProperty() As PropertyDescriptor
|
||||
Get
|
||||
If mSortProperty Is Nothing AndAlso Len(mSortPropertyName) > 0 Then
|
||||
Try
|
||||
' we need to recreate the sortproperty value
|
||||
Dim childType As Type
|
||||
If list.Count > 0 Then
|
||||
' get child type from the first element in the collection
|
||||
childType = list.Item(0).GetType
|
||||
|
||||
Else
|
||||
' get child type from Item property
|
||||
Try
|
||||
childType = Me.GetType.GetProperty("Item", New Type() {GetType(Integer)}).PropertyType
|
||||
|
||||
Catch
|
||||
childType = GetType(Object)
|
||||
End Try
|
||||
End If
|
||||
|
||||
' now get the property descriptor from the type
|
||||
mSortProperty = _
|
||||
TypeDescriptor.GetProperties(childType).Item(mSortPropertyName)
|
||||
|
||||
Catch
|
||||
' we failed to recreate it - return nothing
|
||||
mSortProperty = Nothing
|
||||
End Try
|
||||
End If
|
||||
Return mSortProperty
|
||||
End Get
|
||||
End Property
|
||||
|
||||
''' <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 Overrides ReadOnly Property IBindingList_SortDirection() As ListSortDirection
|
||||
Get
|
||||
Return mListSortDirection
|
||||
End Get
|
||||
End Property
|
||||
|
||||
#End Region
|
||||
|
||||
#Region " ApplySort "
|
||||
|
||||
''' <summary>
|
||||
''' Structure to store temporary data for sorting.
|
||||
''' </summary>
|
||||
Private Structure SortData
|
||||
Private mKey As Object
|
||||
Public Value As Object
|
||||
|
||||
Public Sub New(ByVal Key As Object, ByVal Value As Object)
|
||||
mKey = Key
|
||||
Me.Value = Value
|
||||
End Sub
|
||||
|
||||
Public ReadOnly Property Key() As Object
|
||||
Get
|
||||
If IsNumeric(mKey) OrElse TypeOf mKey Is String Then
|
||||
Return mKey
|
||||
Else
|
||||
Return mKey.ToString
|
||||
End If
|
||||
End Get
|
||||
End Property
|
||||
End Structure
|
||||
|
||||
''' <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
|
||||
Implements IComparer
|
||||
|
||||
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
|
||||
Dim item1 As SortData = DirectCast(x, SortData)
|
||||
Dim item2 As SortData = DirectCast(y, SortData)
|
||||
|
||||
Return Comparer.Default.Compare(item1.Key, item2.Key)
|
||||
|
||||
End Function
|
||||
End Class
|
||||
|
||||
''' <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 Overrides Sub IBindingList_ApplySort(ByVal [property] As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection)
|
||||
|
||||
If Not AllowSort Then
|
||||
Throw New NotSupportedException("Sorting is not supported by this collection.")
|
||||
End If
|
||||
|
||||
mSortProperty = [property]
|
||||
mSortPropertyName = mSortProperty.Name
|
||||
mListSortDirection = direction
|
||||
|
||||
If Not mIsSorted AndAlso list.Count > 0 Then
|
||||
' this is our first time sorting so
|
||||
' make sure to store the original order
|
||||
mUnsortedList = New ArrayList()
|
||||
Dim item As Object
|
||||
For Each item In list
|
||||
mUnsortedList.Add(item)
|
||||
Next
|
||||
End If
|
||||
|
||||
If list.Count > 1 Then
|
||||
Try
|
||||
Dim count As Integer
|
||||
mActivelySorting = True
|
||||
|
||||
' copy the key/value pairs into a sorted list
|
||||
Dim sortList As New ArrayList()
|
||||
For count = 0 To list.Count - 1
|
||||
sortList.Add(New SortData(CallByName(list.Item(count), mSortPropertyName, CallType.Get), list.Item(count)))
|
||||
Next
|
||||
sortList.Sort(New SortDataCompare())
|
||||
|
||||
list.Clear()
|
||||
|
||||
If direction = ListSortDirection.Ascending Then
|
||||
Dim item As SortData
|
||||
For Each item In sortList
|
||||
list.Add(item.Value)
|
||||
Next
|
||||
|
||||
Else ' direction = ListSortDirection.Descending
|
||||
Dim item As SortData
|
||||
For count = sortList.Count - 1 To 0 Step -1
|
||||
item = DirectCast(sortList(count), SortData)
|
||||
list.Add(item.value)
|
||||
Next
|
||||
End If
|
||||
|
||||
mIsSorted = True
|
||||
|
||||
Catch
|
||||
IBindingList_RemoveSort()
|
||||
|
||||
Finally
|
||||
mActivelySorting = False
|
||||
End Try
|
||||
|
||||
ElseIf list.Count = 1 Then
|
||||
mIsSorted = True
|
||||
End If
|
||||
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#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 Overrides Sub IBindingList_RemoveSort()
|
||||
|
||||
If Not AllowSort Then
|
||||
Throw New NotSupportedException("Sorting is not supported by this collection.")
|
||||
End If
|
||||
|
||||
If mIsSorted Then
|
||||
mActivelySorting = True
|
||||
|
||||
'Return the list to its unsorted state
|
||||
list.Clear()
|
||||
|
||||
Dim item As Object
|
||||
For Each item In mUnsortedList
|
||||
list.Add(item)
|
||||
Next
|
||||
|
||||
mUnsortedList = Nothing
|
||||
|
||||
mIsSorted = False
|
||||
mSortProperty = Nothing
|
||||
mSortPropertyName = ""
|
||||
mListSortDirection = ListSortDirection.Ascending
|
||||
mActivelySorting = False
|
||||
End If
|
||||
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region " Collection events "
|
||||
|
||||
''' <summary>
|
||||
''' Ensures that any sort is maintained as a new item is inserted.
|
||||
''' </summary>
|
||||
Protected Overrides Sub OnInsertComplete(ByVal index As Integer, ByVal value As Object)
|
||||
If mIsSorted AndAlso Not ActivelySorting Then
|
||||
mUnsortedList.Add(value)
|
||||
End If
|
||||
MyBase.OnInsertComplete(index, value)
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Ensures that any sort is maintained as the list is cleared.
|
||||
''' </summary>
|
||||
Protected Overrides Sub OnClearComplete()
|
||||
If mIsSorted AndAlso Not ActivelySorting Then
|
||||
mUnsortedList.Clear()
|
||||
End If
|
||||
MyBase.OnClearComplete()
|
||||
End Sub
|
||||
|
||||
''' <summary>
|
||||
''' Ensures that any sort is maintained as an item is removed.
|
||||
''' </summary>
|
||||
Protected Overrides Sub OnRemoveComplete(ByVal index As Integer, ByVal value As Object)
|
||||
If mIsSorted AndAlso Not ActivelySorting Then
|
||||
mUnsortedList.Remove(value)
|
||||
End If
|
||||
MyBase.OnRemoveComplete(index, value)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
#Region " Search/Find "
|
||||
|
||||
''' <summary>
|
||||
''' Implements search/find functionality for the collection.
|
||||
''' </summary>
|
||||
Protected Overrides Function IBindingList_Find(ByVal [property] As PropertyDescriptor, ByVal key As Object) As Integer
|
||||
|
||||
If Not AllowFind Then
|
||||
Throw New NotSupportedException("Searching is not supported by this collection.")
|
||||
End If
|
||||
|
||||
Dim index As Integer
|
||||
Dim tmp As Object
|
||||
Dim prop As String = [property].Name
|
||||
|
||||
For index = 0 To list.Count - 1
|
||||
tmp = CallByName(list.Item(index), prop, CallType.Get)
|
||||
If tmp.Equals(key) Then
|
||||
' we found a match
|
||||
Return index
|
||||
End If
|
||||
Next
|
||||
|
||||
' we didn't find anything
|
||||
Return -1
|
||||
|
||||
End Function
|
||||
|
||||
#End Region
|
||||
|
||||
End Class
|
||||
|
||||
End Namespace
|
||||
Reference in New Issue
Block a user