Editing sub-items in a listview using Visual Basic (VB.NET)

Although I know much more about StarBasic than I do about VB.NET, I am working a project in VB.NET. I decided that I wanted to provide edit controls in a ListView. The easy solution is to set the LabelEdit property to true and then in a double click handler (or similar), you add code like this:

  1. ListViewVarName.SelectedItems(0).BeginEdit()

Although this is easy, this only works for the first column. My list view has multiple columns of different types, so, I used something a bit more extreme. First, I added a text box control (TextBoxOverlay) and a date edit control (DateTimePickerOverlay) onto my form and set them to be NOT visible. Next, I created a handler
  1. Dim selCol As Integer = 0
  2. Dim selItem As ListViewItem = Nothing
  3.  
  4. Private Sub ListViewDBRuns_MouseDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListViewDBRuns.MouseDoubleClick
  5.  
  6.     ' Returns information about where the mouse was clicked.
  7.     ' Wow, this is easy, I don't even have to work for it.
  8.     Dim hit As ListViewHitTestInfo = ListViewDBRuns.HitTest(e.X, e.Y)
  9.  
  10.     Dim iCol As Integer
  11.     Dim iWidth As Integer
  12.  
  13.     For iCol = 0 To hit.Item.SubItems.Count - 1
  14.         'OK, now this is a problem. The first item
  15.         'has a left point of zero and a right point as wide as ALL of the sub-items.
  16.         'First, verify that the mouse was to the right of the left-most point for the column.
  17.         If hit.Item.SubItems(iCol).Bounds.Left <= e.X Then
  18.             If iCol = 0 And hit.Item.SubItems.Count > 1 Then
  19.  
  20.                 'Clicked in column zero and there are more than one columns. 
  21.                 'Check to see if clicked right of the next sub-item (because the right of item-0 is the entire row).
  22.                 If e.X <= hit.Item.SubItems(1).Bounds.Left Then
  23.                     iWidth = hit.Item.SubItems(1).Bounds.Left
  24.                     Exit For
  25.                 End If
  26.             ElseIf e.X <= hit.Item.SubItems(iCol).Bounds.Right Then
  27.                 'We are to the right of the edge for this sub-item.
  28.                 'I don't want them to edit column 4.
  29.                 If iCol = 4 Then
  30.                     Exit Sub
  31.                 Else
  32.                     iWidth = hit.Item.SubItems(iCol).Bounds.Width
  33.                     Exit For
  34.                 End If
  35.             End If
  36.         End If
  37.     Next
  38.  
  39.     'Remember the clicked column and item.
  40.     selCol = iCol
  41.     selItem = hit.Item
  42.  
  43.     'Now, over-lay an edit control on top of the clicked item.
  44.     If iCol = 3 Then
  45.         DateTimePickerOverlay.Left = ListViewDBRuns.Left + hit.SubItem.Bounds.Left + 3
  46.         DateTimePickerOverlay.Top = ListViewDBRuns.Top + hit.SubItem.Bounds.Top
  47.         DateTimePickerOverlay.Width = iWidth
  48.         DateTimePickerOverlay.Text = hit.SubItem.Text
  49.         DateTimePickerOverlay.Visible = True
  50.         DateTimePickerOverlay.Focus()
  51.     Else
  52.         TextBoxOverlay.Left = ListViewDBRuns.Left + hit.SubItem.Bounds.Left + 3
  53.         TextBoxOverlay.Top = ListViewDBRuns.Top + hit.SubItem.Bounds.Top
  54.         TextBoxOverlay.Width = iWidth
  55.         TextBoxOverlay.Text = hit.SubItem.Text
  56.         TextBoxOverlay.Visible = True
  57.         TextBoxOverlay.Focus()
  58.         TextBoxOverlay.SelectAll()
  59.     End If
  60. End Sub

There is still much more work to do to make this usable, like notice when the control is no longer focused, persisting the data back into the list view, and then hiding the editor, but, I will leave that to you. I posted this specifically because there are so many ways to do this.