65.9K
CodeProject is changing. Read more.
Home

WinForms ListView Find & GetSubItemRect

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.31/5 (9 votes)

Jan 23, 2005

2 min read

viewsIcon

101705

downloadIcon

1299

Overcoming some limitations of the WinForms ListView control.

Sample Image - LVFind.gif

Introduction

Do you want to find an Item in a ListView control without writing a loop to search through the Items collection? Do you need to get the bounding rectangle of an Item or SubItem (in Details view) in a ListView control? Well then, this article is for you!

Background

VB 6 supports a Find() method to find an Item in a ListView control. However, this method is no longer present in VB.NET. So you could write a code to loop through the Items collection, comparing each Item's text with your search text, e.g.:

     For Each itm As ListViewItem In ListView1.Items
         If exactMatch Then
            If itm.Text = mySearchText Then
               ' an exact match was found ...

            End If
         Else
            mySearchText &= "*"
            If itm.Text Like mySearchText Then
               ' a partial match was found ...

            End If
         End If
     Next

where mySearchText is the text you are searching for, and exactMatch is a Boolean you've defined to determine if an exact or partial match is to be made. Also, although the ListView Item supports the GetBounds() method to return a rectangle with the bounds of the ListView Item, e.g.:

myRect = ListView1.Items(0).GetBounds(ItemBoundsPortion.Entire)

Unfortunately, ListView SubItem does not, so:

myRect = ListView1.Items(0).SubItems(1).GetBounds(ItemBoundsPortion.Entire)

produces the following error:

'GetBounds' is not a member of 'System.Windows.Forms.ListViewItem.ListViewSubItem'.

Using the code

To use the LVFindItem class, add a new class to your project and replace the generated code with the contents of LVFind.vb. Then, in the code for your form containing a ListView control, add a code similar to the following.

To search for a string in the ListView Items collection:

   Dim fPar As Integer = LVFind.LVFindItem.LVFI_PARTIAL
   Dim mySearchString As String = "findme"
   ...
   Sub Find()
      FindIt(mySearchString, fPar)
   End Sub
   ...
   ' Search for SearchString in ListView1 Items

   Private Sub FindIt(ByVal SearchString As String, _
    Optional ByVal flag As Integer = LVFind.LVFindItem.LVFI_PARTIAL)
      ' Make an instance of the LVFindItem class

      Dim lvf As New LVFind.LVFindItem
      ' Call the LVFnd() sub

      '   1st parm is ListView control

      '   2nd parm is text to find

      '   3rd parm (optional) is flag value (see LVFindItem class for definition)

      lvf.LVFnd(ListView1, SearchString, flag)
      ' Focus the ListView control so we can see which item is selected

      ListView1.Focus()
   End Sub

To get the bounding rectangle of a ListView Item or SubItem:

   Dim itmIdx As Integer = 1 ' The index of the Item in the Items collection

   Dim colNum As Integer = 2 ' The column of the Item or SubItem

   Dim myRect As Rectangle ' Holds the return value from Locate()

   ...
   Sub GetRect()
      myRect = Locate(itmIdx, colNum)
   End Sub
   ...
   'Get bounding rectangle of Item itm, Column col

   Private Function Locate(ByVal itm As Integer, ByVal col As Integer) As Rectangle
      ' Make an instance of the LVFindItem class

      Dim lvf As New LVFind.LVFindItem
      ' A new Rectangle to hold the return value from GetSubItemRect

      Dim rect As New Rectangle
      ' Call the GetSubItemRect() function

      '   1st parm is ListView control

      '   2nd parm is index of Item to find

      '   3rd parm is column of SubItem to find

      '   4th parm (optional) is flag value (see LVFindItem class for definition)

      rect = lvf.GetSubItemRect(ListView1, itm, col, LVFind.LVFindItem.LVIR_LABEL)
      Return rect
   End Function

Points of Interest

Interestingly, on MSDN, under the definition of the LVM_GETSUBITEMRECT message, the definition of the LVIR_LABEL flag value states that it is identical to LVIR_BOUNDS. This is incorrect, at least when the ListView control is in Details view. Try changing the flag's value in the LVFind test code (hint: I'm already using LVIR_LABEL, so change it to LVIR_BOUNDS and give it a try).

History

23rd Jan 2005 - First release.