none
ListView 的虚模式VirtualMode 怎样排序和显示复选框 RRS feed

答案

  • 各位前辈,我做了一个应用,因为要添加比较多的数据到listview,所以想用虚模式,但是不能显示复选框和排序,我找到有C#版本的能显示复选框(http://www.codeproject.com/Articles/18115/ListView-in-VirtualMode-and-checkboxes),但是不能排序,而且转换成vb。net也不行,所以请教下大家,listview在此模式下,要怎样才能显示复选框和排序。非常感谢。

    Hi,

    我看了下里面的链接,并将对应的C#代码通过http://converter.telerik.com/   转换并作了部分修改,一部分是对应VB.NET中的方法,另一部分是为了之后的排序。

    Public Class Form1

    ’为了排序做准备改变原先的类型使之能够进行排序

    Private lvi As New List(Of ListViewItem) Private listView1 As New ListView

    排序需要使用的类 Private m_lvwColumnSorter As New ListViewColumnSorter Private Sub listView_RetrieveVirtualItem(sender As Object, e As RetrieveVirtualItemEventArgs) e.Item = lvi(e.ItemIndex) End Sub Private Sub listView_DrawItem(sender As Object, e As DrawListViewItemEventArgs) e.DrawDefault = True If Not e.Item.Checked Then e.Item.Checked = True e.Item.Checked = False End If End Sub Private Sub listView_MouseClick(sender As Object, e As MouseEventArgs) Dim lv As ListView = DirectCast(sender, ListView) Dim lvi As ListViewItem = lv.GetItemAt(e.X, e.Y) If lvi IsNot Nothing Then If e.X < (lvi.Bounds.Left + 16) Then lvi.Checked = Not lvi.Checked lv.Invalidate(lvi.Bounds) End If End If End Sub Private Sub listView_MouseDoubleClick(sender As Object, e As MouseEventArgs) Dim lv As ListView = DirectCast(sender, ListView) Dim lvi As ListViewItem = lv.GetItemAt(e.X, e.Y) If lvi IsNot Nothing Then lv.Invalidate(lvi.Bounds) End If End Sub Private Sub SetupListview(blnVirtual As Boolean) ' Get ListView working Me.listView1 = New ListView() Me.listView1.Dock = DockStyle.Fill ' This is what we want!! Me.listView1.View = View.List Me.listView1.CheckBoxes = True If blnVirtual Then ' This makes it real fast!! AddHandler Me.listView1.RetrieveVirtualItem, AddressOf listView_RetrieveVirtualItem 'Me.listView1.RetrieveVirtualItem += New RetrieveVirtualItemEventHandler(AddressOf listView_RetrieveVirtualItem) Me.listView1.VirtualListSize = lvi.Count Me.listView1.VirtualMode = True ' This is what you need, for drawing unchecked checkboxes Me.listView1.OwnerDraw = True AddHandler Me.listView1.DrawItem, AddressOf listView_DrawItem 'Me.listView1.DrawItem += New DrawListViewItemEventHandler(AddressOf listView_DrawItem) ' Redraw when checked or doubleclicked AddHandler Me.listView1.MouseClick, AddressOf listView_MouseClick AddHandler Me.listView1.MouseDoubleClick, AddressOf listView_MouseDoubleClick ' Me.listView1.MouseClick += New MouseEventHandler(AddressOf listView_MouseClick) ' Me.listView1.MouseDoubleClick += New MouseEventHandler(AddressOf listView_MouseDoubleClick) Else ' The other way Me.listView1.Items.AddRange(lvi.ToArray()) End If ' Show in main form End Sub Private Sub Test() With listView1 .Columns.Add("Test") End With ' You can switch between Virtual and Normal Dim blnVirtual As Boolean = True ' Get the ListViewItem cache up and running Dim NR As Integer = 100 For intI As Integer = 0 To 100 - 1 lvi.Add(New ListViewItem(intI & " test")) Next ' Check some random items, just for testing lvi(3).Checked = True lvi(5).Checked = True lvi(12).Checked = True lvi(NR - 2).Checked = True Dim stopwatch As New Stopwatch() stopwatch.Reset() stopwatch.Start() SetupListview(blnVirtual) Me.Controls.Add(Me.listView1) stopwatch.[Stop]() Me.Text = "ListView VirtualMode=" & blnVirtual & " : " & lvi.Count & " items in " & stopwatch.ElapsedMilliseconds & " mS" End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load Test() End Sub End Class

    以下是排序需要的类:

    Imports System.Collections
    Imports System.Windows.Forms
    Imports System.Collections.Generic
    Imports System.Text
    ''' <summary>
    ''' This class is an implementation of the 'IComparer' interface.
    ''' </summary>
    Public Class ListViewColumnSorter
        Implements IComparer(Of ListViewItem)
        ''' <summary>
        ''' Specifies the column to be sorted
        ''' </summary>
        Private ColumnToSort As Integer
        ''' <summary>
        ''' Specifies the order in which to sort (i.e. 'Ascending').
        ''' </summary>
        Private OrderOfSort As SortOrder
        ''' <summary>
        ''' Case insensitive comparer object
        ''' </summary>
        Private ObjectCompare As CaseInsensitiveComparer
    
        ''' <summary>
        ''' Class constructor.  Initializes various elements
        ''' </summary>
        Public Sub New()
            ' Initialize the column to '0'
            ColumnToSort = 0
    
            ' Initialize the sort order to 'none'
            OrderOfSort = SortOrder.None
    
            ' Initialize the CaseInsensitiveComparer object
            ObjectCompare = New CaseInsensitiveComparer()
        End Sub
    
        ''' <summary>
        ''' This method is inherited from the IComparer interface.  It compares the two objects passed using a case insensitive comparison.
        ''' </summary>
        ''' <param name="x">First object to be compared</param>
        ''' <param name="y">Second object to be compared</param>
        ''' <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
        Public Function Compare(x As ListViewItem, y As ListViewItem) As Integer Implements IComparer(Of ListViewItem).Compare
            Dim compareResult As Integer
            Dim listviewX As ListViewItem, listviewY As ListViewItem
    
            ' Cast the objects to be compared to ListViewItem objects
            listviewX = DirectCast(x, ListViewItem)
            listviewY = DirectCast(y, ListViewItem)
    
            ' Compare the two items
            If ColumnToSort > 0 Then
                compareResult = CompareTwoObjects(listviewX.SubItems(ColumnToSort - 1).Tag, listviewY.SubItems(ColumnToSort - 1).Tag)
            Else
                compareResult = CompareTwoObjects(listviewX.Text, listviewY.Text)
            End If
            ' Calculate correct return value based on object comparison
            If OrderOfSort = SortOrder.Ascending Then
                ' Ascending sort is selected, return normal result of compare operation
                Return compareResult
            ElseIf OrderOfSort = SortOrder.Descending Then
                ' Descending sort is selected, return negative result of compare operation
                Return (-compareResult)
            Else
                ' Return '0' to indicate they are equal
                Return 0
            End If
        End Function
    
        'Compare object depend upon their types.
        Private Function CompareTwoObjects(x As Object, y As Object) As Integer
            Dim res As Integer = 0
            If x.[GetType]() = GetType(String) Then
                res = Comparer.[Default].Compare(x, y)
            ElseIf x.[GetType]() = GetType(Integer) Then
                Dim t1 As Integer = CInt(x)
                Dim t2 As Integer = CInt(y)
                If t1 = t2 Then
                    res = 0
                ElseIf t1 < t2 Then
                    res = -1
                Else
                    res = 1
                End If
            ElseIf x.[GetType]() = GetType(DateTime) Then
                Dim d1 As DateTime = DirectCast(x, DateTime)
                Dim d2 As DateTime = DirectCast(y, DateTime)
                If d1 = d2 Then
                    res = 0
                ElseIf d1 < d2 Then
                    res = -1
                Else
                    res = 1
                End If
            End If
            Return res
        End Function
        ''' <summary>
        ''' Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
        ''' </summary>
        Public Property SortColumn() As Integer
            Get
                Return ColumnToSort
            End Get
            Set(value As Integer)
                ColumnToSort = value
            End Set
        End Property
    
        ''' <summary>
        ''' Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
        ''' </summary>
        Public Property Order() As SortOrder
            Get
                Return OrderOfSort
            End Get
            Set(value As SortOrder)
                OrderOfSort = value
            End Set
        End Property
    
    End Class
    

    要实现排序可以添加以下的代码来实现针对某个column来排序:
     Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            m_lvwColumnSorter.SortColumn = 0
            m_lvwColumnSorter.Order = SortOrder.Descending
            lvi.Sort(m_lvwColumnSorter)
            listView1.VirtualListSize = 0
            listView1.Update()
            listView1.VirtualListSize = Me.lvi.Count
            listView1.Update()
        End Sub

    效果图:

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 gqdsc 2014年4月26日 2:43
    2014年4月25日 8:19
    版主

全部回复

  • 各位前辈,我做了一个应用,因为要添加比较多的数据到listview,所以想用虚模式,但是不能显示复选框和排序,我找到有C#版本的能显示复选框(http://www.codeproject.com/Articles/18115/ListView-in-VirtualMode-and-checkboxes),但是不能排序,而且转换成vb。net也不行,所以请教下大家,listview在此模式下,要怎样才能显示复选框和排序。非常感谢。

    Hi,

    我看了下里面的链接,并将对应的C#代码通过http://converter.telerik.com/   转换并作了部分修改,一部分是对应VB.NET中的方法,另一部分是为了之后的排序。

    Public Class Form1

    ’为了排序做准备改变原先的类型使之能够进行排序

    Private lvi As New List(Of ListViewItem) Private listView1 As New ListView

    排序需要使用的类 Private m_lvwColumnSorter As New ListViewColumnSorter Private Sub listView_RetrieveVirtualItem(sender As Object, e As RetrieveVirtualItemEventArgs) e.Item = lvi(e.ItemIndex) End Sub Private Sub listView_DrawItem(sender As Object, e As DrawListViewItemEventArgs) e.DrawDefault = True If Not e.Item.Checked Then e.Item.Checked = True e.Item.Checked = False End If End Sub Private Sub listView_MouseClick(sender As Object, e As MouseEventArgs) Dim lv As ListView = DirectCast(sender, ListView) Dim lvi As ListViewItem = lv.GetItemAt(e.X, e.Y) If lvi IsNot Nothing Then If e.X < (lvi.Bounds.Left + 16) Then lvi.Checked = Not lvi.Checked lv.Invalidate(lvi.Bounds) End If End If End Sub Private Sub listView_MouseDoubleClick(sender As Object, e As MouseEventArgs) Dim lv As ListView = DirectCast(sender, ListView) Dim lvi As ListViewItem = lv.GetItemAt(e.X, e.Y) If lvi IsNot Nothing Then lv.Invalidate(lvi.Bounds) End If End Sub Private Sub SetupListview(blnVirtual As Boolean) ' Get ListView working Me.listView1 = New ListView() Me.listView1.Dock = DockStyle.Fill ' This is what we want!! Me.listView1.View = View.List Me.listView1.CheckBoxes = True If blnVirtual Then ' This makes it real fast!! AddHandler Me.listView1.RetrieveVirtualItem, AddressOf listView_RetrieveVirtualItem 'Me.listView1.RetrieveVirtualItem += New RetrieveVirtualItemEventHandler(AddressOf listView_RetrieveVirtualItem) Me.listView1.VirtualListSize = lvi.Count Me.listView1.VirtualMode = True ' This is what you need, for drawing unchecked checkboxes Me.listView1.OwnerDraw = True AddHandler Me.listView1.DrawItem, AddressOf listView_DrawItem 'Me.listView1.DrawItem += New DrawListViewItemEventHandler(AddressOf listView_DrawItem) ' Redraw when checked or doubleclicked AddHandler Me.listView1.MouseClick, AddressOf listView_MouseClick AddHandler Me.listView1.MouseDoubleClick, AddressOf listView_MouseDoubleClick ' Me.listView1.MouseClick += New MouseEventHandler(AddressOf listView_MouseClick) ' Me.listView1.MouseDoubleClick += New MouseEventHandler(AddressOf listView_MouseDoubleClick) Else ' The other way Me.listView1.Items.AddRange(lvi.ToArray()) End If ' Show in main form End Sub Private Sub Test() With listView1 .Columns.Add("Test") End With ' You can switch between Virtual and Normal Dim blnVirtual As Boolean = True ' Get the ListViewItem cache up and running Dim NR As Integer = 100 For intI As Integer = 0 To 100 - 1 lvi.Add(New ListViewItem(intI & " test")) Next ' Check some random items, just for testing lvi(3).Checked = True lvi(5).Checked = True lvi(12).Checked = True lvi(NR - 2).Checked = True Dim stopwatch As New Stopwatch() stopwatch.Reset() stopwatch.Start() SetupListview(blnVirtual) Me.Controls.Add(Me.listView1) stopwatch.[Stop]() Me.Text = "ListView VirtualMode=" & blnVirtual & " : " & lvi.Count & " items in " & stopwatch.ElapsedMilliseconds & " mS" End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load Test() End Sub End Class

    以下是排序需要的类:

    Imports System.Collections
    Imports System.Windows.Forms
    Imports System.Collections.Generic
    Imports System.Text
    ''' <summary>
    ''' This class is an implementation of the 'IComparer' interface.
    ''' </summary>
    Public Class ListViewColumnSorter
        Implements IComparer(Of ListViewItem)
        ''' <summary>
        ''' Specifies the column to be sorted
        ''' </summary>
        Private ColumnToSort As Integer
        ''' <summary>
        ''' Specifies the order in which to sort (i.e. 'Ascending').
        ''' </summary>
        Private OrderOfSort As SortOrder
        ''' <summary>
        ''' Case insensitive comparer object
        ''' </summary>
        Private ObjectCompare As CaseInsensitiveComparer
    
        ''' <summary>
        ''' Class constructor.  Initializes various elements
        ''' </summary>
        Public Sub New()
            ' Initialize the column to '0'
            ColumnToSort = 0
    
            ' Initialize the sort order to 'none'
            OrderOfSort = SortOrder.None
    
            ' Initialize the CaseInsensitiveComparer object
            ObjectCompare = New CaseInsensitiveComparer()
        End Sub
    
        ''' <summary>
        ''' This method is inherited from the IComparer interface.  It compares the two objects passed using a case insensitive comparison.
        ''' </summary>
        ''' <param name="x">First object to be compared</param>
        ''' <param name="y">Second object to be compared</param>
        ''' <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
        Public Function Compare(x As ListViewItem, y As ListViewItem) As Integer Implements IComparer(Of ListViewItem).Compare
            Dim compareResult As Integer
            Dim listviewX As ListViewItem, listviewY As ListViewItem
    
            ' Cast the objects to be compared to ListViewItem objects
            listviewX = DirectCast(x, ListViewItem)
            listviewY = DirectCast(y, ListViewItem)
    
            ' Compare the two items
            If ColumnToSort > 0 Then
                compareResult = CompareTwoObjects(listviewX.SubItems(ColumnToSort - 1).Tag, listviewY.SubItems(ColumnToSort - 1).Tag)
            Else
                compareResult = CompareTwoObjects(listviewX.Text, listviewY.Text)
            End If
            ' Calculate correct return value based on object comparison
            If OrderOfSort = SortOrder.Ascending Then
                ' Ascending sort is selected, return normal result of compare operation
                Return compareResult
            ElseIf OrderOfSort = SortOrder.Descending Then
                ' Descending sort is selected, return negative result of compare operation
                Return (-compareResult)
            Else
                ' Return '0' to indicate they are equal
                Return 0
            End If
        End Function
    
        'Compare object depend upon their types.
        Private Function CompareTwoObjects(x As Object, y As Object) As Integer
            Dim res As Integer = 0
            If x.[GetType]() = GetType(String) Then
                res = Comparer.[Default].Compare(x, y)
            ElseIf x.[GetType]() = GetType(Integer) Then
                Dim t1 As Integer = CInt(x)
                Dim t2 As Integer = CInt(y)
                If t1 = t2 Then
                    res = 0
                ElseIf t1 < t2 Then
                    res = -1
                Else
                    res = 1
                End If
            ElseIf x.[GetType]() = GetType(DateTime) Then
                Dim d1 As DateTime = DirectCast(x, DateTime)
                Dim d2 As DateTime = DirectCast(y, DateTime)
                If d1 = d2 Then
                    res = 0
                ElseIf d1 < d2 Then
                    res = -1
                Else
                    res = 1
                End If
            End If
            Return res
        End Function
        ''' <summary>
        ''' Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
        ''' </summary>
        Public Property SortColumn() As Integer
            Get
                Return ColumnToSort
            End Get
            Set(value As Integer)
                ColumnToSort = value
            End Set
        End Property
    
        ''' <summary>
        ''' Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
        ''' </summary>
        Public Property Order() As SortOrder
            Get
                Return OrderOfSort
            End Get
            Set(value As SortOrder)
                OrderOfSort = value
            End Set
        End Property
    
    End Class
    

    要实现排序可以添加以下的代码来实现针对某个column来排序:
     Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            m_lvwColumnSorter.SortColumn = 0
            m_lvwColumnSorter.Order = SortOrder.Descending
            lvi.Sort(m_lvwColumnSorter)
            listView1.VirtualListSize = 0
            listView1.Update()
            listView1.VirtualListSize = Me.lvi.Count
            listView1.Update()
        End Sub

    效果图:

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 gqdsc 2014年4月26日 2:43
    2014年4月25日 8:19
    版主
  • 太感谢你了,果然可用,只是我的2005中,类那里要修改下:x.[GetType]() Is GetType(String),非常非常感谢!!
    2014年4月26日 2:43