Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Help sorting a list view

Posted on 2012-09-18
16
Medium Priority
?
424 Views
Last Modified: 2012-10-02
I am able to sort my list view by clicking the column and it sorts all of the rows and sub items.  The code seems to work great until I try to repopulate the listview.  Each line I add to the listview tries to create a new sort and takes a long time.  I dont notice with a small list, but one of them is about 1000 rows and it takes to long to populate whiles its sortting at the same time.  Is there a way to turn off this sort as I populate the listview and then the user can click on the sort column again?  Here is the code I use to create the sort.


' Implements a comparer for ListView columns.
Class ListViewComparer
    Implements IComparer

    Private m_ColumnNumber As Integer
    Private m_SortOrder As SortOrder

    Public Sub New(ByVal column_number As Integer, ByVal _
        sort_order As SortOrder)
        m_ColumnNumber = column_number
        m_SortOrder = sort_order
    End Sub

    ' Compare the items in the appropriate column
    ' for objects x and y.
    Public Function Compare(ByVal x As Object, ByVal y As _
        Object) As Integer Implements _
        System.Collections.IComparer.Compare
        Dim item_x As ListViewItem = DirectCast(x,  _
            ListViewItem)
        Dim item_y As ListViewItem = DirectCast(y,  _
            ListViewItem)

        ' Get the sub-item values.
        Dim string_x As String
        If item_x.SubItems.Count <= m_ColumnNumber Then
            string_x = ""
        Else
            string_x = item_x.SubItems(m_ColumnNumber).Text
        End If

        Dim string_y As String
        If item_y.SubItems.Count <= m_ColumnNumber Then
            string_y = ""
        Else
            string_y = item_y.SubItems(m_ColumnNumber).Text
        End If

        ' Compare them.
        If m_SortOrder = SortOrder.Ascending Then
            If IsNumeric(string_x) And IsNumeric(string_y) _
                Then
                Return Val(string_x).CompareTo(Val(string_y))
            ElseIf IsDate(string_x) And IsDate(string_y) _
                Then
                Return DateTime.Parse(string_x).CompareTo(DateTime.Parse(string_y))
            Else
                Return String.Compare(string_x, string_y)
            End If
        Else
            If IsNumeric(string_x) And IsNumeric(string_y) _
                Then
                Return Val(string_y).CompareTo(Val(string_x))
            ElseIf IsDate(string_x) And IsDate(string_y) _
                Then
                Return DateTime.Parse(string_y).CompareTo(DateTime.Parse(string_x))
            Else
                Return String.Compare(string_y, string_x)
            End If
        End If
    End Function
End Class



 ' The column currently used for sorting.
    Private m_SortingColumn As ColumnHeader

    ' Sort using the clicked column.
    Private Sub listview1_ColumnClick(ByVal sender As  _
        System.Object, ByVal e As  _
        System.Windows.Forms.ColumnClickEventArgs) Handles ListView1.ColumnClick
        ' Get the new sorting column.
        Dim new_sorting_column As ColumnHeader = _
            ListView1.Columns(e.Column)

        ' Figure out the new sorting order.
        Dim sort_order As System.Windows.Forms.SortOrder
        If m_SortingColumn Is Nothing Then
            ' New column. Sort ascending.
            sort_order = SortOrder.Ascending
        Else
            ' See if this is the same column.
            If new_sorting_column.Equals(m_SortingColumn) Then
                ' Same column. Switch the sort order.
                If m_SortingColumn.Text.StartsWith("> ") Then
                    sort_order = SortOrder.Descending
                Else
                    sort_order = SortOrder.Ascending
                End If
            Else
                ' New column. Sort ascending.
                sort_order = SortOrder.Ascending
            End If

            ' Remove the old sort indicator.
            m_SortingColumn.Text = _
                m_SortingColumn.Text.Substring(2)
        End If

        ' Display the new sort order.
        m_SortingColumn = new_sorting_column
        If sort_order = SortOrder.Ascending Then
            m_SortingColumn.Text = "> " & m_SortingColumn.Text
        Else
            m_SortingColumn.Text = "< " & m_SortingColumn.Text
        End If

        ' Create a comparer.
        ListView1.ListViewItemSorter = New  _
            ListViewComparer(e.Column, sort_order)

        ' Sort.
        ListView1.Sort()
    End Sub
0
Comment
Question by:chadmanvb
  • 8
  • 5
  • 3
16 Comments
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 38411111
Have you tried wrapping your adding code in BeginUpdate() / EndUpdate() calls?
http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.beginupdate(VS.71).aspx
0
 

Author Comment

by:chadmanvb
ID: 38411190
Well should I populate my list view differently?  Currently I do one row at a time.  How can I make this add them all at the same time?  Or whats the best practice?  Here is how I fill it now.
 Public Sub cloneusers()

        ListView7.Items.Clear()
        Dim strCounter As Integer = 0
        Dim item1 As ListViewItem

        '*******************READ CSV***********************************
        Dim workStations As New FileStream("\\server\UserCheck\tsmembers.log", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
        Dim workStationsRead As New StreamReader(workStations)
        Dim workStationsList As String = workStationsRead.ReadToEnd()
        workStationsRead.Close()
        workStations.Close()

        Dim workStationListSplit() As String = Regex.Split(workStationsList, "\r\n")

        For Each FileLine As String In workStationListSplit

            Dim cols = Split(FileLine, ",")

            If FileLine = "" Then
                'skip blank lines
            Else

                strCounter = strCounter + 1
                item1 = New ListViewItem
                item1.Text = cols(0).ToString
                item1.SubItems.Add(cols(1)).ToString()
                item1.SubItems.Add(cols(3)).ToString()
                item1.SubItems.Add(cols(2)).ToString()
                ListView7.Items.Add(item1)

            End If
        Next

        Label23.Text = "Total Clone Remote Access Members= " & strCounter


    End Sub
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 38411200
I would try the path of least resistance first:
    ListView7.BeginUpdate()

    For Each FileLine As String In workStationListSplit

            Dim cols = Split(FileLine, ",")

            If FileLine = "" Then
                'skip blank lines
            Else

                strCounter = strCounter + 1
                item1 = New ListViewItem
                item1.Text = cols(0).ToString
                item1.SubItems.Add(cols(1)).ToString()
                item1.SubItems.Add(cols(3)).ToString()
                item1.SubItems.Add(cols(2)).ToString()
                ListView7.Items.Add(item1)

            End If
        Next

    ListView7.EndUpdate()
    ListView7.Refresh()

Open in new window

0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 

Author Comment

by:chadmanvb
ID: 38411272
Still gives me the same problem.  I can call the sub and it populates the listview in about 1 second.  I can click on the sort columns and it sorts in about a second.  Once I sort and try to repopulate the listview it takes about 20 seconds.  If I never tried to sort the data and just keep refreshing it, it only takes about a second.  I'm guessing my sort it trying to sort as it refreshes.  Any ideas?
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 38411299
Hmmm...ok.  Let's go on step further on the extreme side then:
    Private Const WM_SETREDRAW As Integer = &HB

    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal handle As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Open in new window


Then replace BeginUpdate()/EndUpdate() with SendMessage():
    SendMessage(ListView7.Handle, WM_SETREDRAW, False, 0) ' Turn OFF updates

    For Each FileLine As String In workStationListSplit

            Dim cols = Split(FileLine, ",")

            If FileLine = "" Then
                'skip blank lines
            Else

                strCounter = strCounter + 1
                item1 = New ListViewItem
                item1.Text = cols(0).ToString
                item1.SubItems.Add(cols(1)).ToString()
                item1.SubItems.Add(cols(3)).ToString()
                item1.SubItems.Add(cols(2)).ToString()
                ListView7.Items.Add(item1)

            End If
        Next

    SendMessage(ListView7.Handle, WM_SETREDRAW, True, 0) ' Turn ON updates
    ListView7.Refresh()

Open in new window

0
 

Author Comment

by:chadmanvb
ID: 38411344
Bummer, same issue.  It seems like it's trying to sort as it's adding each item...just a guess.  If I never click on the row to do the sort it almost works instantly when I refresh the listview.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 38411357
What if you set Sorting() to None, add your items, then reset it back to what it was?

*Still may need the BeginUpdate()/EndUpdate() wrap to keep it from updating.
0
 

Author Comment

by:chadmanvb
ID: 38411405
I wanted to try that,  but I'm not sure how to stop the sorter.  How do I stop and start it back to it's last sort?
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 38411422
Hmmm...try:
        Dim PrevSortOrder As SortOrder = ListView7.Sorting
        ListView7.Sorting = SortOrder.None

        ' ...

        ListView7.Sorting = PrevSortOrder

Open in new window

0
 

Author Comment

by:chadmanvb
ID: 38411487
I tried that, but I dont think that works for the sort class I'm using listed at the top of the post.  I think that's was giving me grief.
0
 
LVL 83

Accepted Solution

by:
CodeCruiser earned 2000 total points
ID: 38412838
You may also have to set

ListView1.ListViewItemSorter = Nothing

and then back to your object.
0
 

Author Comment

by:chadmanvb
ID: 38413343
Code, I think your on to something.  That almost works.  So now run my sub to popluate the listview, then I can click on the columns to do a sort, and when I rerun my sub to re-populate the listview it's fast, but does not use the last sort I clicked on.  I can still see the the < or > sign on the column, so it still remembers it.  It just does not resort it after it fills.  I tried listview7.sort() but that did not work either.
0
 
LVL 83

Expert Comment

by:CodeCruiser
ID: 38414183
After filling it, add

ListView1.ListViewItemSorter = New  ListViewComparer(SortColumn, sort_order)
ListView1.Sort()

You may have to declare SortColumn at class level and set it to e.Column when sorting the list from UI.
0
 

Author Comment

by:chadmanvb
ID: 38428752
Sorry for the delay, but still can't get it to resort after I refill the table.  I tried to add.

ListView1.ListViewItemSorter = New  ListViewComparer(SortColumn, sort_order)
ListView1.Sort()

but ListViewComparer is not defined.  Also I'm not sure how to do the second part you mentioned.
You may have to declare SortColumn at class level and set it to e.Column when sorting the list from UI.
0
 
LVL 83

Expert Comment

by:CodeCruiser
ID: 38437452
What I meant was to declare

Dim SortColumn As Integer

at class level (just below the Public Class line)

Then in your listview1_ColumnClick method, add

SortColumn = e.Column

You may also have to do this for SortOrder

Then after refill, add

ListView1.ListViewItemSorter = New  ListViewComparer(SortColumn, sort_order)
ListView1.Sort()
0
 

Author Closing Comment

by:chadmanvb
ID: 38456606
Thanks for the help!
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…
Suggested Courses

580 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question