How to use a ComboBox control to edit data in a ListView control in Visual Basic 2005 or in Visual Basic .NET (320342)



The information in this article applies to:

  • Microsoft Visual Basic 2005
  • Microsoft Visual Basic .NET (2003)
  • Microsoft Visual Basic .NET (2002)

This article was previously published under Q320342
For a Microsoft Visual C# 2005 and Microsoft Visual C# .NET version of this article, see 320344.

SUMMARY

This step-by-step article demonstrates how to use a ComboBox control to edit the data in a ListView control. This method replaces the standard text box approach of editing the data in a ListView control.

Description of the technique

By using the LabelEdit property of the ListView control, you can let the user edit the contents of the ListView control. To edit the data in the ListView control, you can use a standard text box. Occasionally, it is useful to have another control to edit the control. This article simulates how to use a ComboBox control to edit the data in a ListView when the ListView is in Details view.

When the user selects a row in the ListView, a calculation is performed to locate the bounding rectangle for the first column of the row that is clicked. That calculation takes into account that the column may not be visible or may not be fully visible when the row is clicked and when the ComboBox is sized and displayed appropriately.

In addition to positioning and sizing the ComboBox, this sample also watches for two messages on the ListView control: WM_VSCROLL and WM_HSCROLL. These messages occur whenever the user scrolls through the ListView control vertically or horizontally. Because the ComboBox is not physically part of the ListView control, the ComboBox does not automatically scroll with the ListView. Therefore, whenever either of these two messages occur, the ComboBox must be hidden. To watch for these messages, you create a custom UserControl class that inherits from the ListView class. In this custom control, the WndProc method is overridden to allow all messages to be checked for scrolling.

Create the inherited ListView control

  1. Start Microsoft Visual Studio 2005 or Microsoft Visual Studio .NET.
  2. On the File menu, point to New, and then click Project.
  3. In the New Project dialog box, click Visual Basic Projects under Project Types, and then click Windows Control Library under Templates.

    Note In Visual Studio 2005, click Visual Basic instead of Visual Basic Projects.
  4. Replace all the code in the UserControl class with the following code.
    Imports System
    Imports System.Collections
    Imports System.ComponentModel
    Imports System.Drawing
    Imports System.Data
    Imports System.Windows.Forms
    
    Public Class MyListView
        Inherits System.Windows.Forms.ListView
    
    #Region " Windows Form Designer generated code "
    
        Public Sub New()
            MyBase.New()
    
            'This call is required by the Windows Form Designer.
            InitializeComponent()
    
            'Add any initialization after the InitializeComponent() call
    
        End Sub
    
        'UserControl1 overrides dispose to clean up the component list.
        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If Not (components Is Nothing) Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(disposing)
        End Sub
    
        'Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer
    
        'NOTE: The following procedure is required by the Windows Form Designer
        'It can be modified using the Windows Form Designer.  
        'Do not modify it using the code editor.
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            components = New System.ComponentModel.Container()
        End Sub
    
    #End Region
    
        Private Const WM_HSCROLL As Integer = &H114
        Private Const WM_VSCROLL As Integer = &H115
    
        Protected Overrides Sub WndProc(ByRef msg As Message)
            ' Look for the WM_VSCROLL or the WM_HSCROLL messages.
            If ((msg.Msg = WM_VSCROLL) Or (msg.Msg = WM_HSCROLL)) Then
                ' Move focus to the ListView to cause ComboBox to lose focus.
                Me.Focus()
            End If
    
            ' Pass message to default handler.
            MyBase.WndProc(msg)
        End Sub
    End Class
    					
  5. Save and then build the project.

Create the sample application

  1. Follow these steps to create a Windows Application in Visual Basic 2005 or in Visual Basic .NET:
    1. On the File menu, point to New, and then click Project.
    2. In the New Project dialog box, click Visual Basic Projects under Project Types, and then click Windows Application under Templates. By default, Form1 is created.

      Note In Visual Studio 2005, click Visual Basic instead of Visual Basic Projects.

      Note You must change the code in Visual Basic 2005. By default, Visual Basic creates two files for the project when you create a Windows Forms project. If the form is named Form1, the two files that represent the form are named Form1.vb and Form1.Designer.vb. You write the code in the Form1.vb file. The Windows Forms Designer writes the code in the Form1.Designer.vb file. The Windows Forms Designer uses the partial keyword to divide the implementation of Form1 into two separate files. This behavior prevents the designer-generated code from being interspersed with your code.

      For more information about the new Visual Basic 2005 language enhancements, visit the following Microsoft Developer Network (MSDN) Web site: For more information about partial classes and the Windows Forms Designer, visit the following MSDN Web site:
  2. Follow these steps to add the control that you created in the "Create the inherited ListView control" section to your Windows application:
    1. On the Tools menu, click Customize Toolbox.
    2. On the .NET Framework Components tab, click Browse.
    3. In the Open dialog box, locate the control that you created in the "Create the inherited ListView control" section, and then click Open. This adds this control to the toolbox so that you can use the control similarly to any other control.
    4. Drag MyListView from the General section of the toolbox to Form1.
  3. Drag a ComboBox control from the Windows Forms section of the toolbox to Form1.
  4. In the Properties window of ComboBox, change the Name property to cbListViewCombo, and then set the Visible property to False.
  5. Add the following code to the class of Form1 before the "Windows Form Designer generated code" section:
    Private lvItem As ListViewItem
    					
  6. Add the following code to the Load event of Form1.
    ' Add a few items to the combo box list.
    Me.cbListViewCombo.Items.Add("NC")
    Me.cbListViewCombo.Items.Add("WA")
    
    ' Set view of ListView to Details.
    Me.MyListView1.View = View.Details
    
    ' Turn on full row select.
    Me.MyListView1.FullRowSelect = True
    
    ' Add some data to the ListView.
    Dim columnheader As ColumnHeader
    Dim lviewitem As ListViewItem
    
    ' Create sample ListView data.
    lviewitem = New ListViewItem("NC")
    lviewitem.SubItems.Add("North Carolina")
    Me.MyListView1.Items.Add(lviewitem)
    
    lviewitem = New ListViewItem("WA")
    lviewitem.SubItems.Add("Washington")
    Me.MyListView1.Items.Add(lviewitem)
    
    ' Create column headers for the data.
    columnheader = New ColumnHeader()
    columnheader.Text = "State Abbr."
    Me.MyListView1.Columns.Add(columnheader)
    
    columnheader = New ColumnHeader()
    columnheader.Text = "State"
    Me.MyListView1.Columns.Add(columnheader)
    
    ' Loop through and size each column header to fit the column header text.
    Dim ch As ColumnHeader
    
    For Each ch In Me.MyListView1.Columns
       ch.Width = -2
    Next
    					
  7. Add the following code to the SelectedValueChanged event of the ComboBox control.
    ' Set text of ListView item to match the ComboBox.
    lvItem.Text = Me.cbListViewCombo.Text
    
    ' Hide the ComboBox.
    Me.cbListViewCombo.Visible = False
    					
  8. Add the following code to the Leave event of the ComboBox control.
    ' Set text of ListView item to match the ComboBox.
    lvItem.Text = Me.cbListViewCombo.Text
    
    ' Hide the ComboBox.
    Me.cbListViewCombo.Visible = False
    					
  9. Add the following code to the KeyPress event of the ComboBox control.
    ' Verify that the user presses ESC.
    Select Case (e.KeyChar)
       Case ChrW(CType(Keys.Escape, Integer))
          ' Reset the original text value, and then hide the ComboBox.
          Me.cbListViewCombo.Text = lvItem.Text
          Me.cbListViewCombo.Visible = False
    
       Case ChrW(CType(Keys.Enter, Integer))
          ' Hide the ComboBox.
          Me.cbListViewCombo.Visible = False
    End Select
    					
  10. Add the following code to the MouseUp event of myListView1.
    ' Get the item on the row that is clicked.
    lvItem = Me.MyListView1.GetItemAt(e.X, e.Y)
    
    ' Make sure that an item is clicked.
    If Not (lvItem Is Nothing) Then
       ' Get the bounds of the item that is clicked.
       Dim ClickedItem As Rectangle = lvItem.Bounds
    
       ' Verify that the column is completely scrolled off to the left.
       If ((ClickedItem.Left + Me.MyListView1.Columns(0).Width) < 0) Then
          ' If the cell is out of view to the left, do nothing.
          Return
    
       ' Verify that the column is partially scrolled off to the left.
       ElseIf (ClickedItem.Left < 0) Then
          ' Determine if column extends beyond right side of ListView.
          If ((ClickedItem.Left + Me.MyListView1.Columns(0).Width) > Me.MyListView1.Width) Then                   
             ' Set width of column to match width of ListView.
             ClickedItem.Width = Me.MyListView1.Width
             ClickedItem.X = 0
          Else
             ' Right side of cell is in view.
             ClickedItem.Width = Me.MyListView1.Columns(0).Width + ClickedItem.Left
             ClickedItem.X = 2
          End If
    
       ElseIf (Me.MyListView1.Columns(0).Width > Me.MyListView1.Width) Then
          ClickedItem.Width = Me.MyListView1.Width
      
       Else
          ClickedItem.Width = Me.MyListView1.Columns(0).Width
          ClickedItem.X = 2
       End If
    
       ' Adjust the top to account for the location of the ListView.
       ClickedItem.Y += Me.MyListView1.Top
       ClickedItem.X += Me.MyListView1.Left
    
       ' Assign calculated bounds to the ComboBox.
       Me.cbListViewCombo.Bounds = ClickedItem
    
       ' Set default text for ComboBox to match the item that is clicked.
       Me.cbListViewCombo.Text = lvItem.Text
    
       ' Display the ComboBox, and make sure that it is on top with focus.
       Me.cbListViewCombo.Visible = True
       Me.cbListViewCombo.BringToFront()
       Me.cbListViewCombo.Focus()
    End If
    					

Verify that it works

  1. Save and then run the sample.
  2. Click a row in the ListView control. Notice that a combo box appears over the location of the first column of the current row.
  3. To hide the combo box, click an item in the combo box, press ESC, and then scroll through the ListView control or click another control. Notice that the value that you clicked in the combo box is placed in the first column of the clicked row of the ListView control.

Modification Type:MinorLast Reviewed:10/3/2006
Keywords:kbvs2005swept kbvs2005applies kbHOWTOmaster KB320342 kbAudDeveloper