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
Get
Return m_blnCatchChanges
End Get
Set(ByVal value As Boolean)
m_blnCatchChanges = value
Dim clsI As clsBaseClass
For Each clsI In MyBase.Items
clsI.CatchChanges = m_blnCatchChanges
Next
End Set
End Property
''' <name>Property ThrowEveryChangesEvent</name>
''' <returns>Boolean</returns>
''' <summary>
''' Indique qu'un evenement doit être raised à chaque changement, ou
seulement le premier fois...
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Property ThrowEveryChangesEvent() As Boolean
Get
Return m_blnThrowEveryChangesEvent
End Get
Set(ByVal value As Boolean)
m_blnThrowEveryChangesEvent = value
End Set
End Property
'<System.ComponentModel.DefaultValue(False)> _
Public Event HasChangesEvent As EventHandler(Of HasChangesEventArgs)
''' <name>Property HasChanges</name>
''' <returns>Boolean</returns>
''' <summary>
''' True s'il y a des changements qui se sont passés aux propertys de
la classe.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Property HasChanges() As Boolean
Get
Return m_blnHasChanges
End Get
Set(ByVal value As Boolean)
m_blnHasChanges = value
End Set
End Property
''' <name>Property EntiteName</name>
''' <returns>String</returns>
''' <summary>
''' Le nom de l'entité de la classe.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Property EntiteName() As String
Get
Return m_strEntiteName
End Get
Set(ByVal value As String)
m_strEntiteName = value
End Set
End Property
''' <name>Property EntiteCe</name>
''' <returns>String</returns>
''' <summary>
''' CET adresse, CE fournisseur, ...
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Property EntiteCe() As String
Get
Return m_strEntiteCe
End Get
Set(ByVal value As String)
m_strEntiteCe = value
End Set
End Property
#End Region
#Region "Base Collection Methods"
''' <name>Function TestCloseCollection</name>
''' <returns>Integer</returns>
''' <summary>
''' This Methode tests for unsaved changes when CatchChanges is True,
and ask to save unchanged changes.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Function TestCloseCollection() As Integer
If Me.m_blnCatchChanges And Me.m_blnHasChanges Then
Dim intA As Integer
intA = MessageBox.Show("Vous avez fait des changements depuis
le dernier sauvegarde." & vbCrLf & "Est-ce que vous voulez les
sauvegarder?", "Sauvegarder changements?", MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Warning)
If intA = vbYes Then
'raise event to save the changes
'RaiseEvent Click_Save()
If Me.Save() Then
'if succesfully saved: class can be
disposed/finalized...
Return vbYes
Else
'if not: don't close it...
Return vbCancel
End If
ElseIf intA = vbNo Then
'if they don't want to save the changes: disable the
changes-handler
Me.CatchChanges = False
Return intA
Else
Return intA
End If
Else
Return vbYes
End If
End Function
''' <name>Function Save</name>
''' <returns>Boolean</returns>
''' <summary>
''' ' Update les changements ou insert les dans la base de données pour
tout les objets dans la collection.
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Function Save() As Boolean
Try
Me.SaveBegin()
Dim clsI As clsBaseClass
For Each clsI In MyBase.Items
If Not clsI.Save() Then SavedSuccesfull = False
Next
Catch ex As Exception
'ErrorMessage(ex)
SavedSuccesfull = False
Throw ex
End Try
Me.SaveEnd()
Return SavedSuccesfull
End Function
''' <name>Function Delete</name>
''' <returns>Boolean</returns>
''' <summary>
''' Supprime tout les éléments dans la liste
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Function Delete() As Boolean
Try
Me.DeleteBegin()
Dim clsI As clsBaseClass
For Each clsI In MyBase.Items
If Not clsI.Delete Then
Me.DeletedSuccesfull = False
Return Me.DeletedSuccesfull
Exit Function
End If
Next
'remove them all
Me.Clear()
Catch ex As Exception
'ErrorMessage(ex)
Me.DeletedSuccesfull = False
Throw ex
End Try
Return Me.DeletedSuccesfull
End Function
''' <name>Function Delete</name>
''' <returns>Boolean</returns>
''' <summary>
''' Deletes a specified Object in the List
''' </summary>
''' <param name="item">ByVal item As T: The item that must be
deleted</param>
''' <history>
''' PCO Created
''' </history>
Public Function Delete(ByVal item As T) As Boolean
Try
Me.DeleteBegin()
If Not item.Delete Then Me.DeletedSuccesfull = False
Me.Remove(item)
Catch ex As Exception
'ErrorMessage(ex)
Me.DeletedSuccesfull = False
Throw ex
End Try
Return Me.DeletedSuccesfull
End Function
''' <name>Sub SetCollectionToUnchangedState</name>
''' <summary>
''' Methode qui remets le HasChanges = False et CatchChanges = True
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public Sub SetCollectionToUnchangedState()
'reset it
CatchChanges = True
HasChanges = False
End Sub
Private Sub OnObjectInListChangedHandler(ByVal sender As Object, ByVal
e As HasChangesEventArgs)
'always...
''regarde si on n'as pas déjà fait...
''If (Not m_blnHasChanges) Then 'il y a une valeur qui est changé!
''ok, il y a une valeur changé
HasChanges = True
RaiseEvent HasChangesEvent(sender, e)
''End If
End Sub
Private Sub OnObjectInListSelectedChangedHandler(ByVal sender As
Object, ByVal e As HasChangesEventArgs)
'always...
RaiseEvent HasChangesSelectedEvent(sender, e)
End Sub
Public Event HasChangesSelectedEvent As EventHandler(Of
HasChangesEventArgs)
''' <name>ReadOnly Property SelectedCount()</name>
''' <returns>Integer</returns>
''' <summary>
''' Property qui retourne le nombre d'Items dans la collection qui a le
property Selected = True
''' </summary>
''' <history>
''' PCO Created
''' </history>
Public ReadOnly Property SelectedCount() As Integer
Get
Dim clsB As clsBaseClass
Dim intC As Integer = 0
For Each clsB In MyBase.Items
If clsB.Selected Then
intC += 1
End If
Next
Return intC
End Get
End Property
#End Region
#Region "List Methods"
Public Shadows Sub Add(ByVal item As T)
item.SetClassToUnchangedState()
AddHandler item.HasChangesEvent, AddressOf
OnObjectInListChangedHandler
AddHandler item.SelectedChanged, AddressOf
OnObjectInListSelectedChangedHandler
MyBase.Add(item)
End Sub
Public Shadows Sub Insert(ByVal index As Integer, ByVal item As T)
item.SetClassToUnchangedState()
AddHandler item.HasChangesEvent, AddressOf
OnObjectInListChangedHandler
AddHandler item.SelectedChanged, AddressOf
OnObjectInListSelectedChangedHandler
MyBase.Insert(index, item)
End Sub
Public Shadows Sub Clear()
For Each item As clsBaseClass In Me
RemoveHandler item.HasChangesEvent, AddressOf
OnObjectInListChangedHandler
RemoveHandler item.SelectedChanged, AddressOf
OnObjectInListSelectedChangedHandler
Next
MyBase.Clear()
End Sub
Public Shadows Function Remove(ByVal item As T) As Boolean
RemoveHandler item.HasChangesEvent, AddressOf
OnObjectInListChangedHandler
RemoveHandler item.SelectedChanged, AddressOf
OnObjectInListSelectedChangedHandler
Return MyBase.Remove(item)
End Function
Public Shadows Sub RemoveAt(ByVal index As Integer)
RemoveHandler MyBase.Item(index).HasChangesEvent, AddressOf
OnObjectInListChangedHandler
RemoveHandler MyBase.Item(index).SelectedChanged, AddressOf
OnObjectInListSelectedChangedHandler
MyBase.RemoveAt(index)
End Sub
'very important, otherwise it will return objects of clsBaseClass, and
not object of T...
Default Public Shadows Property Item(ByVal index As Integer) As T
Get
Return MyBase.Item(index)
End Get
Set(ByVal value As T)
AddHandler value.HasChangesEvent, AddressOf
OnObjectInListChangedHandler
AddHandler value.SelectedChanged, AddressOf
OnObjectInListSelectedChangedHandler
MyBase.Item(index) = value
End Set
End Property
#End Region
#Region "Searching"
Protected Overrides ReadOnly Property SupportsSearchingCore() As
Boolean
Get
Return True
End Get
End Property
' Item property descriptor collection cache
Dim pdc As PropertyDescriptorCollection = Nothing
Protected Overrides Function FindCore(ByVal [property] As
PropertyDescriptor, ByVal key As Object) As Integer
' Specify search columns
If ([property] Is Nothing) Then
Return -1
End If
' Get list to search
Dim items As List(Of T) = Me.Items
' Traverse list for value
For Each item As T In items
' Test column search value
Dim value As String = CStr([property].GetValue(item))
'If value is the search value, return the
' index of the data item
If (CStr(key) = value) Then
Return IndexOf(item)
End If
Next item
Return -1
End Function
'ByVal [property] As PropertyDescriptor, ByVal key As Object
Public Function FindItems(ByVal ColumnName As String, ByVal ColumnValue
As Object) As clsBaseList(Of T)
Dim lst As New clsBaseList(Of T)
Dim properties As PropertyDescriptorCollection
Dim myProperty As PropertyDescriptor
' Specify search columns
If (ColumnName Is Nothing) Then
Return Nothing
End If
' Get list to search
Dim items As List(Of T) = Me.Items
' Traverse list for value
For Each item As T In items
properties = TypeDescriptor.GetProperties(item.GetType)
myProperty = properties.Find(ColumnName, False)
' Test column search value
Dim value As String = CStr(myProperty.GetValue(item))
'If value is the search value, return the
' index of the data item
If (CStr(ColumnValue) = value) Then
lst.Add(item)
End If
Next item
Return lst
End Function
Public Function FindItem(ByVal ColumnName As String, ByVal ColumnValue
As Object) As T
Dim properties As PropertyDescriptorCollection =
TypeDescriptor.GetProperties(Me.Items(0).GetType)
Dim myProperty As PropertyDescriptor = properties.Find(ColumnName,
False)
Dim i As Integer = FindCore(myProperty, ColumnValue)
If i = -1 Then
Return Nothing
Else
Return Me.Item(i)
End If
End Function
Public Function SumItems(ByVal ColumnName As String) As Decimal
Dim properties As PropertyDescriptorCollection
Dim myProperty As PropertyDescriptor
' Specify search columns
If (ColumnName Is Nothing) Then
Return Nothing
End If
' Get list to search
Dim items As List(Of T) = Me.Items
' Traverse list for value
Dim decSum As Decimal = 0
For Each item As T In items
properties = TypeDescriptor.GetProperties(item.GetType)
myProperty = properties.Find(ColumnName, False)
'Dim value As String = CStr(myProperty.GetValue(item))
decSum += CSng(myProperty.GetValue(item))
Next item
Return decSum
End Function
#End Region
End Class
Public Class clsListComparer
Implements IComparer
Private m_SortList As ListSortDescriptionCollection
Public Sub New(ByVal SortProperty As PropertyDescriptor, ByVal
direction As ListSortDirection)
'Create a new list every time
m_SortList = New ListSortDescriptionCollection(New
ListSortDescription() {New ListSortDescription(SortProperty, direction)})
End Sub
Public Sub New(ByVal SortList As ListSortDescriptionCollection)
m_SortList = SortList
End Sub
Private Function CompareSingleProperty(ByVal x As clsBaseClass, ByVal y
As clsBaseClass, ByVal prop As PropertyDescriptor, ByVal direction As
ListSortDirection) As Integer
Dim result As Integer = 0
Dim directionModifier As Integer
If (direction = ListSortDirection.Ascending) Then
directionModifier = 1
Else
directionModifier = -1
End If
If (x Is Nothing) Then
result = -1 * directionModifier
ElseIf (y Is Nothing) Then
result = 1 * directionModifier
ElseIf (prop.GetValue(x) < prop.GetValue(y)) Then
result = -1 * directionModifier
ElseIf (prop.GetValue(x) > prop.GetValue(y)) Then
result = 1 * directionModifier
Else
result = 0
End If
Return result
End Function
Private Function Compare(ByVal x As Object, ByVal y As Object) As
Integer _
Implements System.Collections.IComparer.Compare
Dim idx As Integer
Dim result As Integer
If (Not TypeOf x Is clsBaseClass) Then
Throw New ArgumentException("Unexpected Argument. Arguments
must be of Type ", "x")
End If
If (Not TypeOf y Is clsBaseClass) Then
Throw New ArgumentException("Unexpected Argument. Arguments
must be of Type ", "y")
End If
For idx = 0 To m_SortList.Count - 1
result = CompareSingleProperty(x, y,
m_SortList(idx).PropertyDescriptor, m_SortList(idx).SortDirection)
If (result <> 0) Then
Exit For
End If
Next
Return result
End Function
End Class