I am using a list view with several columns in it. I need to be able to sort all the rows based on a user selected column.. Exactly like in Windows Explorer where if you click on "Name" it sorts by name, click on it again and it sorts in the other direction, and the same for all other columns..
Last edited by RudyL; Apr 25th, 2005 at 10:26 AM.
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
I tried to berak pont in the sub that handlesthe column click event but it gives me a message that the breakpoint will never be hit..
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
To get your breakpoint to be hit you need to run the project by pressing F5 or Debug > Run. If your
pressing the exclamation point toolbar button or menu item it will bypass breakpoints.
VB/Office Guru™ (AKA: Gangsta Yoda™ ®)
I dont answer coding questions via PM. Please post a thread in the appropriate forum.
To get your breakpoint to be hit you need to run the project by pressing F5 or Debug > Run. If your
pressing the exclamation point toolbar button or menu item it will bypass breakpoints.
ahh... Not it, but you got me to see why.. I hat it set to Release still.. oopss.. However, It is still not working right.. It will sort the first time I click on it, but if I click again in the same column it will not sort the other way (asc/desc)..
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Have you gone through and checked all the little bits, like you've definitely included the class ListViewItemComparer at the bottom, and the Imports System.Collections at the top?
Have you gone through and checked all the little bits, like you've definitely included the class ListViewItemComparer at the bottom, and the Imports System.Collections at the top?
The M$ example works fine for me.
zaza
I think so.
This is in the form..
VB Code:
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Collections
.......
Private Sub lvTestYields_ColumnClick(ByVal sender As Object, ByVal e As System.Windows.Forms.ColumnClickEventArgs) Handles lvTestYields.ColumnClick
' Set the ListViewItemSorter property to a new ListViewItemComparer
' object. Setting this property immediately sorts the
' ListView using the ListViewItemComparer object.
Me.lvTestYields.ListViewItemSorter = New ListViewItemComparer(e.Column)
End Sub
and I created a class with this in it..
VB Code:
Class ListViewItemComparer
' Implements the manual sorting of items by columns.
Implements IComparer
Private col As Integer
Public Sub New()
col = 0
End Sub
Public Sub New(ByVal column As Integer)
col = column
End Sub
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare
The class stuff wouldn't get put in the form would it?
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
In the columnclick event, after Me.blahblah = New blahblah, put:
lvtestyields.sort()
See if that works.
Fingers Xd
zaza
Nope.. I just noticed another wierd thing.. I have 5 columns.. If I click on column 0 it sorts by column 0 asc.. If I click on column 1 it sorts by column 0 desc.. The same for columns 2 and 3, but they sort based on column 2..
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Actually, having gone back to my sorter, it only sorts ascending. I'm sure I had it working before...
Anyway, try selecting some more data to put into your listview - I think it may just be coincidence that it appears to sort like that. I found a similar "phenomenon" until I changed what was going into the listview. The upshot of what I have found with regard to mine is that it more or less sorts in ascending order. Whichever column is clicked, it will sort mostly alphabetically according to that. By "mostly", I mean that the sorting occurs based only on what is in that column (although in the case of multiple items which are teh same, it sorts on the previous column), but it seems to have slightly odd way of choosing what comes first in the order. Square brackets come above curlies, which come above alphanumeric. I don't know why that is, because it doesn't reflect their ascii codes. In all other respects, though, it seems to sort in ascending order by ascii code based firstly on the column that you choose, then on the preceding column.
Thanks for making me look at my code again. As I say, I thought I'd sorted this out (hohoho). Now I'll have to look at it again.
Cheers
zaza
EDIT:
Ah yes, that's what I did. Create a second comparer class, the same as the first but swap the x and y in the "Return [string]" line. Then, use a flag (such as a public variable called "sortorder") to determine one of two courses of action in your columnclick event. If "sortorder" is 1, then use listviewitemcomparer1 and set "sortorder = -1". If "sortorder = -1", then use listviewitemcomparer2 and set "sortorder = 1". This swaps between the two versions of the sort, enabling you to sort ascending or descending each time you click.
Actually, having gone back to my sorter, it only sorts ascending. I'm sure I had it working before...
Anyway, try selecting some more data to put into your listview - I think it may just be coincidence that it appears to sort like that. I found a similar "phenomenon" until I changed what was going into the listview. The upshot of what I have found with regard to mine is that it more or less sorts in ascending order. Whichever column is clicked, it will sort mostly alphabetically according to that. By "mostly", I mean that the sorting occurs based only on what is in that column (although in the case of multiple items which are teh same, it sorts on the previous column), but it seems to have slightly odd way of choosing what comes first in the order. Square brackets come above curlies, which come above alphanumeric. I don't know why that is, because it doesn't reflect their ascii codes. In all other respects, though, it seems to sort in ascending order by ascii code based firstly on the column that you choose, then on the preceding column.
Thanks for making me look at my code again. As I say, I thought I'd sorted this out (hohoho). Now I'll have to look at it again.
Cheers
zaza
EDIT:
Ah yes, that's what I did. Create a second comparer class, the same as the first but swap the x and y in the "Return [string]" line. Then, use a flag (such as a public variable called "sortorder") to determine one of two courses of action in your columnclick event. If "sortorder" is 1, then use listviewitemcomparer1 and set "sortorder = -1". If "sortorder = -1", then use listviewitemcomparer2 and set "sortorder = 1". This swaps between the two versions of the sort, enabling you to sort ascending or descending each time you click.
HTH
zaza
That worked out perfectly.. I appreciate the help. I made 2 different classes like you suggested. I may post them in the code bank if anyone is interested once I get one ore problem solved..
It works great for string values. However, I have some columns that contain numbers. I have an idea on how to handle that, but I feel it is not all that clean, or even correct. Any thoughts or suggestions on this would be greatly appreciated.
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
No, don't create two classes, use the same one and have an overloaded constructor that accepts an Ascending boolean value. In your Compare implementation, check if it should ascend or not and if it should, you use the former and if it should do a descending sort, then use the latter of the two.
VB Code:
'Ascending Sort
Return String.Compare(Object1, Object2)
'Descending Sort
Return String.Compare(Object2, Object1)
Same principle applies with Integers. You don't need two classes, that just adds to confusion, simply have a variable that checks which sort to do and then perform it.
Have a look at my class for an example of what I mean. It does both text and numerical data.
Note: The attachment has been removed. A more up-to-date version can be found below at post #28
Last edited by Ideas Man; Apr 23rd, 2005 at 03:24 AM.
I use Microsoft Visual Basic 2005. (Therefore, most code samples I provide will be based around the .NET Framework v2.0, unless otherwise specified)
No, don't create two classes, use the same one and have an overloaded constructor that accepts an Ascending boolean value. In your Compare implementation, check if it should ascend or not and if it should, you use the former and if it should do a descending sort, then use the latter of the two.
VB Code:
'Ascending Sort
Return String.Compare(Object1, Object2)
'Descending Sort
Return String.Compare(Object2, Object1)
Same principle applies with Integers. You don't need two classes, that just adds to confusion, simply have a variable that checks which sort to do and then perform it.
Have a look at my class for an example of what I mean. It does both text and numerical data.
Good suggestion... I forgot about overloaded functions and such.. They are nice..
One more question, How would one handle a numerical value that is in percentage?
For example:
cell 1 has 100.00%
Cell 2 has 35.00%
cell 3 has 67.00%
You can't sort it as a number because of the "%"
When you sort as a string is become 100, 67, 35 and 100, 35, 67
The 100% will always be on top..
Edit: It seems that anything with numbers and letters in it is also effected..
Last edited by RudyL; Apr 14th, 2005 at 11:35 AM.
Reason: Add more info
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
One more question.. When dealing with numbers how would I handle an empty cell?
For example:
2
1
1
3
4
The blanl spaces are empty cells and cause the class to crash. I Could change all those empty cells to 0's but then the screen starts to get a bit cluttered. I would prefer a way to handle them as is. I tried to convert.toint32 in the class but it did not work either...
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Its far from done, but it does the things I need it to do at the moment that the regular listview doesn't do.
These include
- Column Sorting on text, date, or numeric values
- added a Scroll event that fires when you scroll the listview (why did they leave that out?)
- Added a ColumnsResized event that will fire if you resize a column (good if you have custom controls like a textbox in the listview...)
I wrote a lot of this when i was less familiar with .net, so if anyone wants to make any suggestions please do. It does work fine though.
VB Code:
Option Strict On
Option Explicit On
Imports System.Windows.Forms
Public Class ListViewScroll
Inherits System.Windows.Forms.ListView
'SCROLL CONSTANTS
Private Const SBM_SETSCROLLINFO As Integer = &HE9
Private Const WM_HSCROLL As Integer = &H115
Private Const WM_VSCROLL As Integer = &H114
'COLUMN RESIZE CONSTANTS
Private Const WM_COLUMNRESIZE As Integer = 78
'EVENTS
Public Event Scroll(ByVal sender As Object, ByVal e As EventArgs)
Public Event ColumnsResized(ByVal sender As Object)
'PRIVATE VARS
Private mSortOrder As SortOrder = SortOrder.None
Private mSortColumnIndex As Integer = 0
Private mAllowSort As Boolean = True
Protected Sub OnScroll()
RaiseEvent Scroll(Me, EventArgs.Empty)
End Sub
Protected Overridable Sub OnColumnHeaderResized()
RaiseEvent ColumnsResized(Me)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.windows.Forms.Message)
MyBase.WndProc(m)
If m.Msg = WM_HSCROLL Or m.Msg = WM_VSCROLL Or m.Msg = SBM_SETSCROLLINFO Then
OnScroll()
ElseIf m.Msg = WM_COLUMNRESIZE Then
OnColumnHeaderResized()
End If
End Sub
Public Property AllowColumnSorting() As Boolean
Get
Return mAllowSort
End Get
Set(ByVal Value As Boolean)
mAllowSort = Value
End Set
End Property
Protected Overrides Sub OnColumnClick(ByVal e As System.Windows.Forms.ColumnClickEventArgs)
If Me.Items.Count = 0 Then Exit Sub
If Not mAllowSort Then Exit Sub
If e.Column = mSortColumnIndex Then
Select Case Me.Sorting
Case SortOrder.None, SortOrder.Descending
Me.Sorting = SortOrder.Ascending
Case Else
Me.Sorting = SortOrder.Descending
End Select
Else
Me.Sorting = SortOrder.Ascending
End If
mSortColumnIndex = e.Column
Dim Sorter As ListViewSorter
Select Case GetColumnType(e.Column)
Case "DATE"
Sorter = New ListViewSorter(e.Column, "DATE", Me.Sorting)
Case "NUMBER"
Sorter = New ListViewSorter(e.Column, "NUMBER", Me.Sorting)
Case Else
Sorter = New ListViewSorter(e.Column, "TEXT", Me.Sorting)
End Select
Me.ListViewItemSorter = Sorter
End Sub
Private Function GetColumnType(ByVal i As Integer) As String
Try
Date.Parse(Me.Items(0).SubItems(i).Text)
Return "DATE"
Catch ex As FormatException
Try
Double.Parse(Me.Items(0).SubItems(i).Text)
Return "NUMBER"
Catch exc As FormatException
Return "TEXT"
End Try
End Try
End Function
Private Class ListViewSorter : Implements System.Collections.IComparer
Public SortIndex As Integer
Private mSortString As String
Private mSortOrder As SortOrder
Public Sub New(ByVal SortIndex As Integer, ByVal DataType As String, ByVal MySortOrder As SortOrder)
Me.SortIndex = SortIndex
mSortString = DataType
mSortOrder = MySortOrder
End Sub
Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare
One more question.. When dealing with numbers how would I handle an empty cell?
For example:
2
1
1
3
4
The blanl spaces are empty cells and cause the class to crash. I Could change all those empty cells to 0's but then the screen starts to get a bit cluttered. I would prefer a way to handle them as is. I tried to convert.toint32 in the class but it did not work either...
Yeah, well, it is a 'work in progress' class sorry. Something I whipped up to do sorts quickly. I guess you could check for nulls or Nothing and if it is the case, return 1 or -1 depending on the sort, that would move them all to either the top or bottom depending on your requirements.
I use Microsoft Visual Basic 2005. (Therefore, most code samples I provide will be based around the .NET Framework v2.0, unless otherwise specified)
Yeah, well, it is a 'work in progress' class sorry. Something I whipped up to do sorts quickly. I guess you could check for nulls or Nothing and if it is the case, return 1 or -1 depending on the sort, that would move them all to either the top or bottom depending on your requirements.
I tried to conver it and could not get it. How would you check for Nulls?
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
well its text sorting... it would probably be empty strings, not nulls that you are looking for...
I understand that, infact I would probably look for either an empty string or a null.. However, my problem is the coding part.. I everything I tried last night caused an error.. (Unfortunatly I did not save any of the code to post )
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
You still workin' on the comparer cause I've gotta update mine tomorrow to support nulls, I'll post the revised copy then.
I am.. I got pulled off of it a few days ago, but plan on getting back into it tonight or tomorrow.. Any code you can provide would be greatly appreciated..
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Here is my latest iteration of the class.. The biggest change is the addition of sorting on a Date/Time field. Thank you Klienma for that, I finally figured that out from your code post..
Unfortunatly, I have not succeeded in getting the "" and NULL fields to sort. I keep getting an error.. (Wrong Type if I remember correctly)
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
OK, I've revised my class, and I also changed one of the arguments for the constructor so you'll need to revise that in your code.
This version will check for missing subitems and sorts accordingly.
It will also sort dates for you.
Give it a go and tell us what you think.
It works great.. Thank you for the help so far. One problem though... I am having trouble understanding how CheckNulls actually works.. (Which may explain why I hadn't been able to get mine to work ).. Your comments make sense to me but what I dont understand is for example this line...
VB Code:
If listViewItem1.SubItems.Count <= _ColumnIndex Then
Return -1
End If
Your comments are this..
Checks to see if the number of items in ListViewItem1 is <= the column index supplied i.e. no subitem exists
at that position. The number of SubItems is <= _ColumnIndex. Returns -1 indicating that it should be moved up
That code is looking at a specific cell right? If it is and the cell is empty then it makes the appropriate decision..
Am I understanding this right?
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Two more things I am working on..
The first which I have no clue how to do it. I want the arrow to show up in the direction of the sort.. Like in windows explorer (see the attachment)..
Also, I am trying to get it to sort on percentages.. Not quite there yet. I looked in the System.Math stuff but have not found anything that can compare the value.
Last edited by RudyL; Apr 21st, 2005 at 03:51 PM.
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Yes you are. It checks to ensure that the index used to sort the row is actually a cell in that row by performing that check.
For example, I had three rows, the top two had three subitems in the row as per the columns laid out, and the bottom only contained two subitems, essentially looking like this:
C1|C2|C3
---------
x | x | x
x | x | x
x | x |
If any row looks like that, or if you simply supply a number such as 5 for the index (which is obviously not a valid column), it checks to see if the number of items in the [row] is less than or equal to the column index to compare.
In my example, if the column was the third column, then the index of the column is 2 and it only has two items, because 2 = 2, it moves the item up because it is a null cell.
Do you understand that?
In response to your little arrow question, I'm unaware of how to do that w/o some 'hacking' of the class.
Also, in what form are the percentages? Are they straight singles like 88.9, or text like 88.9%?
I use Microsoft Visual Basic 2005. (Therefore, most code samples I provide will be based around the .NET Framework v2.0, unless otherwise specified)
Yes you are. It checks to ensure that the index used to sort the row is actually a cell in that row by performing that check.
For example, I had three rows, the top two had three subitems in the row as per the columns laid out, and the bottom only contained two subitems, essentially looking like this:
C1|C2|C3
---------
x | x | x
x | x | x
x | x |
If any row looks like that, or if you simply supply a number such as 5 for the index (which is obviously not a valid column), it checks to see if the number of items in the [row] is less than or equal to the column index to compare.
In my example, if the column was the third column, then the index of the column is 2 and it only has two items, because 2 = 2, it moves the item up because it is a null cell.
Do you understand that?
In response to your little arrow question, I'm unaware of how to do that w/o some 'hacking' of the class.
Also, in what form are the percentages? Are they straight singles like 88.9, or text like 88.9%?
I think I understand the class and NullChecking.. Thanks agian for the help on that.
The percentages are displayed like 88.9%. It's the % that is screwing with me..
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
OK, I've revised it again and went the whole hog and added Single and percentage support for you. I also added code documentation because I made it in VS 2005 and thought what the hell. It should still work though, you just won't see the XML Comments unless you install the VBCommenter tool (See my VB Tip #11) or install VS 2005 Beta 2 (See this topic).
As always, any comments, questions and/or suggestions about it, please let me know how you find it.
Last edited by Ideas Man; Apr 23rd, 2005 at 03:25 AM.
I use Microsoft Visual Basic 2005. (Therefore, most code samples I provide will be based around the .NET Framework v2.0, unless otherwise specified)
How did it go? Are there any other special ways you need them sorted, lol. (I only needed text and numerical, was too lazy to do the rest when I first made it, lol).
I use Microsoft Visual Basic 2005. (Therefore, most code samples I provide will be based around the .NET Framework v2.0, unless otherwise specified)
How did it go? Are there any other special ways you need them sorted, lol. (I only needed text and numerical, was too lazy to do the rest when I first made it, lol).
Sorry, I did not get a chance to actually use it yet. I read through the code ovee the weekend and looks good.. I really need to brush up on my skillz..
Give be about an hour or so and I will have tested it out in my project.
Thanks again for the code You and the others have been a huge help so far
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Ideas man, excelent work on the percentage part! Everything works perfectly. I can't thank you enough.
The only big part I changed was Private _SortOrder As SortOrder = SortOrder.Ascending. I make it a boolean value and use an column array to track the last sort type for each column.. Kind of a preference I think..
I think I am going to start a new thread about the little arrow thingy in the column headder to get some fresh looks..
Thanks again!
Rudy
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Re: Need some list view help.. Please :) -> Resolved
Yeah, I originally had that Boolean value, dunno why I changed it to that, oh well.
Glad to hear it solved your problem. At least now I got a feature complete comparer if I ever need to use any of them other things and it's pretty error proof, lol, so thanks to you for motivating me to do it
I use Microsoft Visual Basic 2005. (Therefore, most code samples I provide will be based around the .NET Framework v2.0, unless otherwise specified)
Re: Need some list view help.. Please :) -> Resolved
Originally Posted by Ideas Man
Yeah, I originally had that Boolean value, dunno why I changed it to that, oh well.
Glad to hear it solved your problem. At least now I got a feature complete comparer if I ever need to use any of them other things and it's pretty error proof, lol, so thanks to you for motivating me to do it
No problem, always happy to motivate others to help me out
If you want, feel free to look here and help with that arrow thingy.. I am begining to come to the conclusion that the C# conversion is outside of my skill set..
Anywho, thank you again for all the help, it is greatly appreciated.
10 different ways to skin a cat and amazingly enough each and every one has the same result, the cat gets skinned! The same can be applied to code, so be nice and accept each others "preferences".
Re: Need some list view help.. Please :) -> Resolved
Originally Posted by d2005
Basically on my list view column 2 is like a date field and and i want to sort this as soon as default
Where does the data come from? Likely it is in some sort of array or collection or database table already right? So sort it by date when you load the data, then load the listview with the already sorted data.