Groups | Blog | Home
all groups > vb.net > march 2006 >

vb.net : Sorting a System.Collections.ObjectModel.Collection


Arthur Dent
3/21/2006 9:51:34 PM
How do you sort a generic collection derived from
System.Collections.ObjectModel.Collection?

Thanks in advance,
- Arthur Dent

Pieter
3/22/2006 12:00:00 AM
Hi,

I made this Generic 'base' List that I use to store collections of objects.
It allows me to sort them, show them in a datagrid/datagridview, search on
propertys, and some stuff to save all the items in the class, see if they
have changes etc. Just pick out the things you need :-)

I hope this helps.

Pieter

Option Explicit On

Imports System.Windows.Forms

Imports System.ComponentModel
Imports System.Collections
Imports System.Collections.Specialized

Public Class clsBaseList(Of T As clsBaseClass)
Inherits BindingList(Of T)
Implements IComponent

Public Sub New()
MyBase.New()
Me.AllowNew = False
Me.AllowRemove = True
End Sub

#Region "IComponent Implementation"
Private m_Site As ISite = Nothing
Public Event Disposed(ByVal sender As Object, ByVal e As
System.EventArgs) _
Implements System.ComponentModel.IComponent.Disposed

Protected Property Site() As System.ComponentModel.ISite Implements _
System.ComponentModel.IComponent.Site
Get
Return m_Site
End Get
Set(ByVal Value As System.ComponentModel.ISite)
m_Site = Value
End Set
End Property

Public Sub Dispose() Implements System.IDisposable.Dispose
Me.Items.Clear()
RaiseEvent Disposed(Me, System.EventArgs.Empty)
End Sub
#End Region

#Region "IBindingList Sorting Features"
Private m_SupportsSorting As Boolean = True
Private m_SortProperty As PropertyDescriptor
Private m_SortDirection As ListSortDirection
Private m_OriginalList As ArrayList

Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
Get
Return m_SupportsSorting
End Get
End Property
Protected Overrides ReadOnly Property SortDirectionCore() As
System.ComponentModel.ListSortDirection
Get
Return m_SortDirection
End Get
End Property

Protected Overrides ReadOnly Property SortPropertyCore() As
System.ComponentModel.PropertyDescriptor
Get
Return m_SortProperty
End Get
End Property

Protected Overrides ReadOnly Property IsSortedCore() As Boolean
Get
Return m_SortProperty Is Nothing
End Get
End Property

Private Sub SaveList()
m_OriginalList = New ArrayList(Me.Items)
End Sub

Private Sub ResetList(ByVal NewList As ArrayList)
Me.ClearItems()
For Each m_T As T In NewList
Me.Add(m_T)
Next
End Sub

Private Sub DoSort()
Dim m_Comparer As New clsListComparer(m_SortProperty,
m_SortDirection)
Dim m_SortList As New ArrayList(Me.Items)
m_SortList.Sort(m_Comparer)
ResetList(m_SortList)
End Sub

Protected Overrides Sub ApplySortCore(ByVal prop As
System.ComponentModel.PropertyDescriptor, ByVal direction As
System.ComponentModel.ListSortDirection)
'toegevoegd door Pieter want sorteerde enkel Ascending in een
DataGridView...
If m_SortProperty IsNot Nothing Then
If (m_SortProperty.Name = prop.Name) And (m_SortDirection =
direction) Then
'wisselen!
direction = (direction + 1) Mod 2
End If
End If

m_SortProperty = prop
m_SortDirection = direction
If (m_OriginalList Is Nothing) Then
SaveList()
End If
DoSort()
End Sub

Protected Overrides Sub RemoveSortCore()
ResetList(m_OriginalList)
m_SortDirection = Nothing
m_SortProperty = Nothing
End Sub
#End Region

#Region "Private Variabel Declarations"
Private m_blnSavedSuccesfull As Boolean
Private m_blnDeletedSuccesfull As Boolean
Private m_blnCatchChanges As Boolean = True
Private m_blnHasChanges As Boolean = False
Private m_strEntiteName As String = "entité"
Private m_strEntiteCe As String = "cette"
Private m_blnSelected As Boolean = True
Private m_blnFilling As Boolean = False
Private m_blnThrowEveryChangesEvent As Boolean = False
#End Region

#Region "Protected Variabel Declarations"

#End Region

#Region "Protected Methods"
''' <name>Sub SaveBegin</name>
''' <summary>
''' Method to call at the beginning of a Save.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Protected Sub SaveBegin()
Me.SavedSuccesfull = True
End Sub

''' <name>Sub SaveEnd</name>
''' <summary>
''' Method to call at the end of a Save. Calls
SetClassToUnchangedState(). Must only be called on SavedSuccesfull.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Protected Sub SaveEnd()
If Me.SavedSuccesfull Then
'Après qu'on a sauvegarder tout les info: donne la message qu'on
a tout bien sauvegarder et qu'on peut remttre le control dans un état "pas
de changements"
SetCollectionToUnchangedState()
Else
'tell the user that his class wasn't saved succesfully!
End If
'raise the event that the save has ended
'RaiseEvent SaveHasEnded(Me, EventArgs.Empty)
End Sub

''' <name>Sub DeleteBegin</name>
''' <summary>
''' Method to call at the beginning of a Delete.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Protected Sub DeleteBegin()
Me.DeletedSuccesfull = True
End Sub
#End Region

#Region "Public Propertys"
''' <name>Property SavedSuccesfull</name>
''' <returns>Boolean</returns>
''' <summary>
''' Indique si la classe a été sauvegarder avec succès.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Property SavedSuccesfull() As Boolean
Get
Return m_blnSavedSuccesfull
End Get
Set(ByVal value As Boolean)
m_blnSavedSuccesfull = value
End Set
End Property

''' <name>Property DeletedSuccesfull</name>
''' <returns>Boolean</returns>
''' <summary>
''' Indique si la classe a été supprimé avec succès.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Property DeletedSuccesfull() As Boolean
Get
Return m_blnDeletedSuccesfull
End Get
Set(ByVal value As Boolean)
m_blnDeletedSuccesfull = value
End Set
End Property

''' <name>Property CatchChanges</name>
''' <returns>Boolean</returns>
''' <summary>
''' Indique si le control doit réagir sur des changements ou pas: par
exemple pas pendant qu'on fait le load d'une entité...
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Property CatchChanges() As Boolean
Arthur Dent
3/23/2006 9:52:17 AM
I could do that, but the thing is that that defeats the point of OO. I was
trying to take advantage of the generic collection as a base so i wouldnt
have to reinvent the wheel..... theres a lot of code involved in coding
collection classes.


[quoted text, click to view]
Pieter
3/24/2006 12:00:00 AM
[quoted text, click to view]

Well, that's exactly what I did: it is taken all the advantages of the
generic classes, it was a bit more difficult, but really worth it (I like
generics): as you can see: "Public Class clsBaseList(Of T As clsBaseClass)".
So I didn't reinvent the wheel here I think :)

Althoug, in my particular case all my objects inherit from clsBaseClass,
which handles a lot of common functionality for my objects.

Jay B. Harlow [MVP - Outlook]
3/24/2006 7:26:58 AM
Arthur,
In addition to the other comments:


Remember that Collection(Of T) is simply a wrapper for an object that
implements IList(Of T). This wrapped IList(Of T) does all the "heavy
lifting" the Collection(Of T) simply delegates to the wrapped IList(Of T).
<sidenote>Read Collection(Of T) uses the Strategy Pattern. The IList(Of T)
is the strategy it uses to implement the list itself, by default its uses an
array like structure for the strategy (the List(Of T), you can easily
replace the strategy with a LinkedList or a Binary tree, see below for
details on replacing the strategy...</sidenote>

You can use Collection(Of T).Items to get at the wrapped IList(Of T).

By default Collection(Of T) uses a List(Of T) as the wrapped IList(Of T),
List(Of T) has a Sort method (plus a plethora of other methods).
Collection(Of T).Items is how you get at the wrapped IList(Of T). In other
words casting Collection(Of T).Items to List(Of T) should allow you to call
its Sort method.

Something like:

Public Class Person
Implements IComparable(Of Person)

...

Public Function CompareTo(ByVal other As Person) As Integer
Implements System.IComparable(Of Person).CompareTo
...
End Function

End Class

Public Class PersonCollection
Inherits ObjectModel.Collection(Of Person)

Public Sub Sort()
DirectCast(Items, List(Of Person)).Sort()
End Sub

End Class

I would consider introducing a new generic collection base that incorporates
this sorting:

Public Class CollectionBase(Of T)
Inherits ObjectModel.Collection(Of T)

Public Sub Sort()
DirectCast(Items, List(Of T)).Sort()
End Sub

Public Sub Sort(ByVal comparer As IComparer(Of T))
DirectCast(Items, List(Of T)).Sort(comparer)
End Sub

Public Sub Sort(ByVal index As Integer, ByVal count As Integer,
ByVal comparer As IComparer(Of T))
DirectCast(Items, List(Of T)).Sort(index, count, comparer)
End Sub

Public Sub Sort(ByVal comparison As Comparison(Of T))
DirectCast(Items, List(Of T)).Sort(comparison)
End Sub

End Class

Then PersonCollection would be based on this new base:

Public Class PersonCollection
Inherits CollectionBase(Of Person)

End Class


NOTE: The above may fail if you call Collection(Of T).New(IList(Of T))
passing in a something other then List(Of T). For example:

Public Class PersonCollection
Inherits ObjectModel.Collection(Of Person)

' use a linked list strategy
Public Sub New()
MyBase.New(New LinkedList(Of Person))
End Sub

' use an array strategy
Public Sub New()
MyBase.New(New Person(100-1) {}) ' base it on an 100 element
array
End Sub

' use some other generic collection strategy
' where SpecializedCollection implements IList(Of T)
Public Sub New()
MyBase.New(New SpecializedCollection(Of Person))
End Sub

End Class

The Frameworks LinkedList(Of T) does not implement IList(Of T) although it
is easy to add. The array does work (as the wrapped list), giving you a
fixed sized collection that you cannot add or remove elements from (you can
only change existing entries)...

I have not yet posted my sample LinkedList(Of T) that implements IList(Of T)
to my web site...

--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


[quoted text, click to view]
| How do you sort a generic collection derived from
| System.Collections.ObjectModel.Collection?
|
| Thanks in advance,
| - Arthur Dent
|
|

Arthur Dent
3/25/2006 12:47:01 AM
Thank you, that was exactly what i was looking for, getting at the inner
list object to be able to use its methods.
Cheers!


"Jay B. Harlow [MVP - Outlook]" <Jay_Harlow_MVP@tsbradley.net> wrote in
message news:eUytha0TGHA.2276@tk2msftngp13.phx.gbl...
[quoted text, click to view]

Jay B. Harlow [MVP - Outlook]
3/25/2006 9:23:30 AM
Arthur,

Thinking about it, it might be better to ensure that you have a wrapped
List(Of T) verses some other IList(Of T) collection... Especially when
introducing a new generic base class...

| > Public Class CollectionBase(Of T)
| > Inherits ObjectModel.Collection(Of T)
| >
Public Sub New()
MyBase.New()
End Sub

Public Sub New(list As IList(Of T))
MyBase.New(list)
End Sub

| > Public Sub Sort()
Dim list As List(Of T) = TryCast(Items, List(Of T))
If list Is Nothing Then Throw New NotSupportedException()
list.Sort()
| > End Sub
| >

--
Hope this helps
Jay [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net


[quoted text, click to view]
| Thank you, that was exactly what i was looking for, getting at the inner
| list object to be able to use its methods.
| Cheers!
|
|
| "Jay B. Harlow [MVP - Outlook]" <Jay_Harlow_MVP@tsbradley.net> wrote in
| message news:eUytha0TGHA.2276@tk2msftngp13.phx.gbl...
| > Arthur,
| > In addition to the other comments:
| >
| >
| > Remember that Collection(Of T) is simply a wrapper for an object that
| > implements IList(Of T). This wrapped IList(Of T) does all the "heavy
| > lifting" the Collection(Of T) simply delegates to the wrapped IList(Of
T).
| > <sidenote>Read Collection(Of T) uses the Strategy Pattern. The IList(Of
| > T)
| > is the strategy it uses to implement the list itself, by default its
uses
| > an
| > array like structure for the strategy (the List(Of T), you can easily
| > replace the strategy with a LinkedList or a Binary tree, see below for
| > details on replacing the strategy...</sidenote>
| >
| > You can use Collection(Of T).Items to get at the wrapped IList(Of T).
| >
| > By default Collection(Of T) uses a List(Of T) as the wrapped IList(Of
T),
| > List(Of T) has a Sort method (plus a plethora of other methods).
| > Collection(Of T).Items is how you get at the wrapped IList(Of T). In
other
| > words casting Collection(Of T).Items to List(Of T) should allow you to
| > call
| > its Sort method.
| >
| > Something like:
| >
| > Public Class Person
| > Implements IComparable(Of Person)
| >
| > ...
| >
| > Public Function CompareTo(ByVal other As Person) As Integer
| > Implements System.IComparable(Of Person).CompareTo
| > ...
| > End Function
| >
| > End Class
| >
| > Public Class PersonCollection
| > Inherits ObjectModel.Collection(Of Person)
| >
| > Public Sub Sort()
| > DirectCast(Items, List(Of Person)).Sort()
| > End Sub
| >
| > End Class
| >
| > I would consider introducing a new generic collection base that
| > incorporates
| > this sorting:
| >
| > Public Class CollectionBase(Of T)
| > Inherits ObjectModel.Collection(Of T)
| >
| > Public Sub Sort()
| > DirectCast(Items, List(Of T)).Sort()
| > End Sub
| >
| > Public Sub Sort(ByVal comparer As IComparer(Of T))
| > DirectCast(Items, List(Of T)).Sort(comparer)
| > End Sub
| >
| > Public Sub Sort(ByVal index As Integer, ByVal count As Integer,
| > ByVal comparer As IComparer(Of T))
| > DirectCast(Items, List(Of T)).Sort(index, count, comparer)
| > End Sub
| >
| > Public Sub Sort(ByVal comparison As Comparison(Of T))
| > DirectCast(Items, List(Of T)).Sort(comparison)
| > End Sub
| >
| > End Class
| >
| > Then PersonCollection would be based on this new base:
| >
| > Public Class PersonCollection
| > Inherits CollectionBase(Of Person)
| >
| > End Class
| >
| >
| > NOTE: The above may fail if you call Collection(Of T).New(IList(Of T))
| > passing in a something other then List(Of T). For example:
| >
| > Public Class PersonCollection
| > Inherits ObjectModel.Collection(Of Person)
| >
| > ' use a linked list strategy
| > Public Sub New()
| > MyBase.New(New LinkedList(Of Person))
| > End Sub
| >
| > ' use an array strategy
| > Public Sub New()
| > MyBase.New(New Person(100-1) {}) ' base it on an 100 element
| > array
| > End Sub
| >
| > ' use some other generic collection strategy
| > ' where SpecializedCollection implements IList(Of T)
| > Public Sub New()
| > MyBase.New(New SpecializedCollection(Of Person))
| > End Sub
| >
| > End Class
| >
| > The Frameworks LinkedList(Of T) does not implement IList(Of T) although
it
| > is easy to add. The array does work (as the wrapped list), giving you a
| > fixed sized collection that you cannot add or remove elements from (you
| > can
| > only change existing entries)...
| >
| > I have not yet posted my sample LinkedList(Of T) that implements
IList(Of
| > T)
| > to my web site...
| >
| > --
| > Hope this helps
| > Jay [MVP - Outlook]
| > .NET Application Architect, Enthusiast, & Evangelist
| > T.S. Bradley - http://www.tsbradley.net
| >
| >
[quoted text, click to view]
| > | How do you sort a generic collection derived from
| > | System.Collections.ObjectModel.Collection?
| > |
| > | Thanks in advance,
| > | - Arthur Dent
| > |
| > |
| >
| >
|
|

AddThis Social Bookmark Button