' ***********************************************************************
' Author : Elektro
' Last Modified On : 08-20-2014
' ***********************************************************************
' <copyright file="ListView Column-Sorter.vb" company="Elektro Studios">
' Copyright (c) Elektro Studios. All rights reserved.
' </copyright>
' ***********************************************************************
#Region " Usage Examples "
'Public Class ListViewColumnSorter_TestForm : Inherits form
'
' ''' <summary>
' ''' The listview to sort.
' ''' </summary>
' Private WithEvents LV As New ListView
'
' ''' <summary>
' ''' The 'ListViewColumnSorter' instance.
' ''' </summary>
' Private Sorter As New ListViewColumnSorter
'
' ''' <summary>
' ''' Initializes a new instance of the <see cref="ListViewColumnSorter_TestForm"/> class.
' ''' </summary>
' Public Sub New()
'
' ' This call is required by the designer.
' InitializeComponent()
'
' With LV ' Set the Listview properties.
'
' ' Set the sorter, our 'ListViewColumnSorter'.
' .ListViewItemSorter = Sorter
'
' ' The sorting default direction.
' .Sorting = SortOrder.Ascending
'
' ' Set the default sort-modifier.
' Sorter.SortModifier = ListViewColumnSorter.SortModifiers.SortByText
'
' ' Add some columns.
' .Columns.Add("Text").Tag = ListViewColumnSorter.SortModifiers.SortByText
' .Columns.Add("Numbers").Tag = ListViewColumnSorter.SortModifiers.SortByNumber
' .Columns.Add("Dates").Tag = ListViewColumnSorter.SortModifiers.SortByDate
'
' ' Adjust the column sizes.
' For Each col As ColumnHeader In LV.Columns
' col.Width = 100I
' Next
'
' ' Add some items.
' .Items.Add("hello").SubItems.AddRange({"1", "11/11/2000"})
' .Items.Add("yeehaa!").SubItems.AddRange({"2", "11-11-2000"})
' .Items.Add("El3ktr0").SubItems.AddRange({"10", "9/9/1999"})
' .Items.Add("wow").SubItems.AddRange({"100", "21/08/2014"})
'
' ' Visual-Style things.
' .Dock = DockStyle.Fill
' .View = View.Details
' .FullRowSelect = True
'
' End With
'
' With Me ' Set the Form properties.
'
' .Size = New Size(400, 200)
' .FormBorderStyle = Windows.Forms.FormBorderStyle.FixedSingle
' .MaximizeBox = False
' .StartPosition = FormStartPosition.CenterScreen
' .Text = "ListViewColumnSorter TestForm"
'
' End With
'
' ' Add the Listview to UI.
' Me.Controls.Add(LV)
'
' End Sub
'
' ''' <summary>
' ''' Handles the 'ColumnClick' event of the 'ListView1' control.
' ''' </summary>
' Private Sub ListView1_ColumnClick(ByVal sender As Object, ByVal e As ColumnClickEventArgs) _
' Handles LV.ColumnClick
'
' ' Dinamycaly sets the sort-modifier to sort the column by text, number, or date.
' Sorter.SortModifier = sender.columns(e.Column).tag
'
' ' Determine whether clicked column is already the column that is being sorted.
' If e.Column = Sorter.Column Then
'
' ' Reverse the current sort direction for this column.
' If Sorter.Order = SortOrder.Ascending Then
' Sorter.Order = SortOrder.Descending
'
' Else
' Sorter.Order = SortOrder.Ascending
'
' End If ' Sorter.Order
'
' Else
'
' ' Set the column number that is to be sorted, default to ascending.
' Sorter.Column = e.Column
' Sorter.Order = SortOrder.Ascending
'
' End If ' e.Column
'
' ' Perform the sort with these new sort options.
' sender.Sort()
'
' End Sub
'
'End Class
#End Region
#Region " Imports "
Imports System.Text.RegularExpressions
Imports System.ComponentModel
#End Region
#Region " ListView Column-Sorter "
''' <summary>
''' Performs a sorting comparison.
''' </summary>
Public Class ListViewColumnSorter : Implements IComparer
#Region " Objects "
'''' <summary>
'''' Indicates the comparer instance.
'''' </summary>
Private Comparer As Object = New TextComparer
#End Region
#Region " Properties "
''' <summary>
''' Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
''' </summary>
Public Property Column As Integer
Get
Return Me._Column
End Get
Set(ByVal value As Integer)
Me._Column = value
End Set
End Property
Private _Column As Integer = 0I
''' <summary>
''' Gets or sets the order of sorting to apply.
''' </summary>
Public Property Order As SortOrder
Get
Return Me._Order
End Get
Set(ByVal value As SortOrder)
Me._Order = value
End Set
End Property
Private _Order As SortOrder = SortOrder.None
''' <summary>
''' Gets or sets the sort modifier.
''' </summary>
''' <value>The sort modifier.</value>
Public Property SortModifier As SortModifiers
Get
Return Me._SortModifier
End Get
Set(ByVal value As SortModifiers)
Me._SortModifier = value
End Set
End Property
Private _SortModifier As SortModifiers = SortModifiers.SortByText
#End Region
#Region " Enumerations "
''' <summary>
''' Specifies a comparison result.
''' </summary>
Public Enum ComparerResult As Integer
''' <summary>
''' 'X' is equals to 'Y'.
''' </summary>
Equals = 0I
''' <summary>
''' 'X' is less than 'Y'.
''' </summary>
Less = -1I
''' <summary>
''' 'X' is greater than 'Y'.
''' </summary>
Greater = 1I
End Enum
''' <summary>
''' Indicates a Sorting Modifier.
''' </summary>
Public Enum SortModifiers As Integer
''' <summary>
''' Treats the values ​​as text.
''' </summary>
SortByText = 0I
''' <summary>
''' Treats the values ​​as numbers.
''' </summary>
SortByNumber = 1I
''' <summary>
''' Treats valuesthe values ​​as dates.
''' </summary>
SortByDate = 2I
End Enum
#End Region
#Region " Private Methods "
''' <summary>
''' Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
''' </summary>
''' <param name="x">The first object to compare.</param>
''' <param name="y">The second object to compare.</param>
''' <returns>
''' A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>,
''' 0: <paramref name="x"/> equals <paramref name="y"/>.
''' Less than 0: <paramref name="x"/> is less than <paramref name="y"/>.
''' Greater than 0: <paramref name="x"/> is greater than <paramref name="y"/>.
''' </returns>
Private Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
Dim CompareResult As ComparerResult = ComparerResult.Equals
Dim LVItemX, LVItemY As ListViewItem
' Cast the objects to be compared
LVItemX = DirectCast(x, ListViewItem)
LVItemY = DirectCast(y, ListViewItem)
Dim strX As String = If(Not LVItemX.SubItems.Count <= Me._Column,
LVItemX.SubItems(Me._Column).Text,
Nothing)
Dim strY As String = If(Not LVItemY.SubItems.Count <= Me._Column,
LVItemY.SubItems(Me._Column).Text,
Nothing)
Dim listViewMain As ListView = LVItemX.ListView
' Calculate correct return value based on object comparison
If listViewMain.Sorting <> SortOrder.Ascending AndAlso listViewMain.Sorting <> SortOrder.Descending Then
' Return '0' to indicate they are equal
Return ComparerResult.Equals
End If
If Me._SortModifier.Equals(SortModifiers.SortByText) Then
' Compare the two items
If LVItemX.SubItems.Count <= Me._Column AndAlso LVItemY.SubItems.Count <= Me._Column Then
CompareResult = Me.Comparer.Compare(Nothing, Nothing)
ElseIf LVItemX.SubItems.Count <= Me._Column AndAlso LVItemY.SubItems.Count > Me._Column Then
CompareResult = Me.Comparer.Compare(Nothing, strY)
ElseIf LVItemX.SubItems.Count > Me._Column AndAlso LVItemY.SubItems.Count <= Me._Column Then
CompareResult = Me.Comparer.Compare(strX, Nothing)
Else
CompareResult = Me.Comparer.Compare(strX, strY)
End If
Else ' Me._SortModifier IsNot 'SortByText'
Select Case Me._SortModifier
Case SortModifiers.SortByNumber
If Me.Comparer.GetType <> GetType(NumericComparer) Then
Me.Comparer = New NumericComparer
End If
Case SortModifiers.SortByDate
If Me.Comparer.GetType <> GetType(DateComparer) Then
Me.Comparer = New DateComparer
End If
Case Else
If Me.Comparer.GetType <> GetType(TextComparer) Then
Me.Comparer = New TextComparer
End If
End Select
CompareResult = Comparer.Compare(strX, strY)
End If ' Me._SortModifier.Equals(...)
' Calculate correct return value based on object comparison
If Me._Order = SortOrder.Ascending Then
' Ascending sort is selected, return normal result of compare operation
Return CompareResult
ElseIf Me._Order = SortOrder.Descending Then
' Descending sort is selected, return negative result of compare operation
Return (-CompareResult)
Else
' Return '0' to indicate they are equal
Return 0I
End If ' Me._Order = ...
End Function
#End Region
#Region " Hidden Methods "
''' <summary>
''' Serves as a hash function for a particular type.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub GetHashCode()
End Sub
''' <summary>
''' Determines whether the specified System.Object instances are considered equal.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub Equals()
End Sub
''' <summary>
''' Gets the System.Type of the current instance.
''' </summary>
''' <returns>The exact runtime type of the current instance.</returns>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Function [GetType]()
Return Me.GetType
End Function
''' <summary>
''' Returns a String that represents the current object.
''' </summary>
<EditorBrowsable(EditorBrowsableState.Never)>
Public Shadows Sub ToString()
End Sub
#End Region
End Class
#End Region
#Region " Comparers "
#Region " Text "
''' <summary>
''' Performs a text comparison.
''' </summary>
Public Class TextComparer : Inherits CaseInsensitiveComparer
#Region " Enumerations "
''' <summary>
''' Specifies a comparison result.
''' </summary>
Public Enum ComparerResult As Integer
''' <summary>
''' 'X' is equals to 'Y'.
''' </summary>
Equals = 0I
''' <summary>
''' 'X' is less than 'Y'.
''' </summary>
Less = -1I
''' <summary>
''' 'X' is greater than 'Y'.
''' </summary>
Greater = 1I
End Enum
#End Region
#Region " Methods "
''' <summary>
''' Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
''' </summary>
''' <param name="x">The first object to compare.</param>
''' <param name="y">The second object to compare.</param>
''' <returns>
''' A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>,
''' 0: <paramref name="x"/> equals <paramref name="y"/>.
''' Less than 0: <paramref name="x"/> is less than <paramref name="y"/>.
''' Greater than 0: <paramref name="x"/> is greater than <paramref name="y"/>.
''' </returns>
Friend Shadows Function Compare(ByVal x As Object, ByVal y As Object) As Integer
' Null parsing.
If x Is Nothing AndAlso y Is Nothing Then
Return ComparerResult.Equals ' X is equals to Y.
ElseIf x Is Nothing AndAlso y IsNot Nothing Then
Return ComparerResult.Less ' X is less than Y.
ElseIf x IsNot Nothing AndAlso y Is Nothing Then
Return ComparerResult.Greater ' X is greater than Y.
End If
' String parsing:
If (TypeOf x Is String) AndAlso (TypeOf y Is String) Then ' True and True
Return [Enum].Parse(GetType(ComparerResult),
MyBase.Compare(x, y))
ElseIf (TypeOf x Is String) AndAlso Not (TypeOf y Is String) Then ' True and False
Return ComparerResult.Greater ' X is greater than Y.
ElseIf Not (TypeOf x Is String) AndAlso (TypeOf y Is String) Then ' False and True
Return ComparerResult.Less ' X is less than Y.
Else ' False and False
Return ComparerResult.Equals
End If
End Function
#End Region
End Class
#End Region
#Region " Numeric "
''' <summary>
''' Performs a numeric comparison.
''' </summary>
Public Class NumericComparer : Implements IComparer
#Region " Enumerations "
''' <summary>
''' Specifies a comparison result.
''' </summary>
Public Enum ComparerResult As Integer
''' <summary>
''' 'X' is equals to 'Y'.
''' </summary>
Equals = 0I
''' <summary>
''' 'X' is less than 'Y'.
''' </summary>
Less = -1I
''' <summary>
''' 'X' is greater than 'Y'.
''' </summary>
Greater = 1I
End Enum
#End Region
#Region " Methods "
''' <summary>
''' Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
''' </summary>
''' <param name="x">The first object to compare.</param>
''' <param name="y">The second object to compare.</param>
''' <returns>
''' A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>,
''' 0: <paramref name="x"/> equals <paramref name="y"/>.
''' Less than 0: <paramref name="x" /> is less than <paramref name="y"/>.
''' Greater than 0: <paramref name="x"/> is greater than <paramref name="y"/>.
''' </returns>
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer _
Implements IComparer.Compare
' Null parsing.
If x Is Nothing AndAlso y Is Nothing Then
Return ComparerResult.Equals ' X is equals to Y.
ElseIf x Is Nothing AndAlso y IsNot Nothing Then
Return ComparerResult.Less ' X is less than Y.
ElseIf x IsNot Nothing AndAlso y Is Nothing Then
Return ComparerResult.Greater ' X is greater than Y.
End If
' The single variables to parse the text.
Dim SingleX, SingleY As Single
' Single parsing:
If Single.TryParse(x, SingleX) AndAlso Single.TryParse(y, SingleY) Then ' True and True
Return [Enum].Parse(GetType(ComparerResult),
SingleX.CompareTo(SingleY))
ElseIf Single.TryParse(x, SingleX) AndAlso Not Single.TryParse(y, SingleY) Then ' True and False
Return ComparerResult.Greater ' X is greater than Y.
ElseIf Not Single.TryParse(x, SingleX) AndAlso Single.TryParse(y, SingleY) Then ' False and True
Return ComparerResult.Less ' X is less than Y.
Else ' False and False
Return [Enum].Parse(GetType(ComparerResult),
x.ToString.CompareTo(y.ToString))
End If
End Function
#End Region
End Class
#End Region
#Region " Date "
''' <summary>
''' Performs a date comparison.
''' </summary>
Public Class DateComparer : Implements IComparer
#Region " Enumerations "
''' <summary>
''' Specifies a comparison result.
''' </summary>
Public Enum ComparerResult As Integer
''' <summary>
''' 'X' is equals to 'Y'.
''' </summary>
Equals = 0I
''' <summary>
''' 'X' is less than 'Y'.
''' </summary>
Less = -1I
''' <summary>
''' 'X' is greater than 'Y'.
''' </summary>
Greater = 1I
End Enum
#End Region
#Region " Methods "
''' <summary>
''' Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
''' </summary>
''' <param name="x">The first object to compare.</param>
''' <param name="y">The second object to compare.</param>
''' <returns>
''' A signed integer that indicates the relative values of <paramref name="x"/> and <paramref name="y"/>,
''' 0: <paramref name="x"/> equals <paramref name="y"/>.
''' Less than 0: <paramref name="x"/> is less than <paramref name="y"/>.
''' Greater than 0: <paramref name="x"/> is greater than <paramref name="y"/>.
''' </returns>
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
' Null parsing.
If x Is Nothing AndAlso y Is Nothing Then
Return ComparerResult.Equals ' X is equals to Y.
ElseIf x Is Nothing AndAlso y IsNot Nothing Then
Return ComparerResult.Less ' X is less than Y.
ElseIf x IsNot Nothing AndAlso y Is Nothing Then
Return ComparerResult.Greater ' X is greater than Y.
End If
' The Date variables to parse the text.
Dim DateX, DateY As Date
' Date parsing:
If Date.TryParse(x, DateX) AndAlso Date.TryParse(y, DateY) Then ' True and True
Return [Enum].Parse(GetType(ComparerResult),
DateX.CompareTo(DateY))
ElseIf Date.TryParse(x, DateX) AndAlso Not Date.TryParse(y, DateY) Then ' True and False
Return ComparerResult.Greater ' X is greater than Y.
ElseIf Not Date.TryParse(x, DateX) AndAlso Date.TryParse(y, DateY) Then ' False and True
Return ComparerResult.Less ' X is less than Y.
Else ' False and False
Return [Enum].Parse(GetType(ComparerResult),
x.ToString.CompareTo(y.ToString))
End If
End Function
#End Region
End Class
#End Region
#End Region