Access ListView SubItem Text by Column Header

Posted on 2006-04-18
Last Modified: 2010-05-26

I have a ListView that I would like to access SubItem text from the selected row.  The ListView is dynamically populated so I am not always sure what SubItem relates to the info I need.  When populating the listview I included column headers but i am not sure how I can reference a selected listview item subItem by column header.

I can get the value with the following line, however i cant guarantee subitems(5) will be the data i need to get.

val = lvwData.Items(SelectedItemIndex).SubItems(5).Text

If I cant do this direct by column header name, is there some way i can determine the SubItems index by the known column name

Thank you for any advise
Question by:QuinnB74
    LVL 27

    Expert Comment

    Hi QuinnB74,

    I do not know if this will help you ,but here is a sample that you might be able to modify...

    'FORM 1

    Public Class frmClickSubItem
        Inherits System.Windows.Forms.Form

    #Region " Windows Form Designer generated code "

        Public Sub New()

            'This call is required by the Windows Form Designer.

            'Add any initialization after the InitializeComponent() call

        End Sub

        'Form 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
                End If
            End If
        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.
        Friend WithEvents ListView1 As System.Windows.Forms.ListView
        Friend WithEvents Label1 As System.Windows.Forms.Label
        Friend WithEvents ColumnHeader1 As System.Windows.Forms.ColumnHeader
        Friend WithEvents ColumnHeader2 As System.Windows.Forms.ColumnHeader
        Friend WithEvents ColumnHeader3 As System.Windows.Forms.ColumnHeader
        Friend WithEvents ColumnHeader4 As System.Windows.Forms.ColumnHeader
        Friend WithEvents ColumnHeader5 As System.Windows.Forms.ColumnHeader
        Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            Me.ListView1 = New System.Windows.Forms.ListView
            Me.ColumnHeader1 = New System.Windows.Forms.ColumnHeader
            Me.ColumnHeader2 = New System.Windows.Forms.ColumnHeader
            Me.ColumnHeader3 = New System.Windows.Forms.ColumnHeader
            Me.ColumnHeader4 = New System.Windows.Forms.ColumnHeader
            Me.ColumnHeader5 = New System.Windows.Forms.ColumnHeader
            Me.Label1 = New System.Windows.Forms.Label
            Me.TextBox1 = New System.Windows.Forms.TextBox
            Me.ListView1.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
                        Or System.Windows.Forms.AnchorStyles.Left) _
                        Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
            Me.ListView1.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.ColumnHeader1, Me.ColumnHeader2, Me.ColumnHeader3, Me.ColumnHeader4, Me.ColumnHeader5})
            Me.ListView1.FullRowSelect = True
            Me.ListView1.GridLines = True
            Me.ListView1.Location = New System.Drawing.Point(8, 8)
            Me.ListView1.MultiSelect = False
            Me.ListView1.Name = "ListView1"
            Me.ListView1.Size = New System.Drawing.Size(458, 206)
            Me.ListView1.TabIndex = 0
            Me.ListView1.View = System.Windows.Forms.View.Details
            Me.Label1.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _
                        Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
            Me.Label1.Location = New System.Drawing.Point(8, 222)
            Me.Label1.Name = "Label1"
            Me.Label1.Size = New System.Drawing.Size(190, 16)
            Me.Label1.TabIndex = 1
            Me.Label1.Text = "Label1"
            Me.TextBox1.Location = New System.Drawing.Point(212, 220)
            Me.TextBox1.Name = "TextBox1"
            Me.TextBox1.TabIndex = 2
            Me.TextBox1.Text = "TextBox1"
            Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
            Me.ClientSize = New System.Drawing.Size(478, 244)
            Me.Name = "frmClickSubItem"
            Me.Text = "Form1"

        End Sub

    #End Region

        Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal lMsg As Integer, ByVal wParam As Integer, ByRef lParam As RECT) As Integer

        Private Structure RECT
            Public Left As Integer
            Public Top As Integer
            Public Right As Integer
            Public Bottom As Integer
        End Structure
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim i As Integer
            Dim lvi As ListViewItem
            Dim ch As ColumnHeader

            For i = 0 To 10
                lvi = New ListViewItem("Item" & i)
                lvi.SubItems.Add("Subitems" & i * 1)
                lvi.SubItems.Add("Subitems" & i * 2)
                lvi.SubItems.Add("Subitems" & i * 3)
                lvi.SubItems.Add("Subitems" & i * 4)

            For Each ch In ListView1.Columns
                ch.Width = -2
        End Sub
        Private Sub ListView1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseDown
            Label1.Text = "Column " & (GetListViewSubItem(Me.ListView1, New Point(e.X, e.Y)) + 1)
        End Sub

        Public Function GetListViewSubItem(ByVal listView1 As ListView, ByVal pt As Point) As Integer
            Const LVM_FIRST As Integer = &H1000
            Const LVM_GETSUBITEMRECT As Integer = LVM_FIRST + 56
            Const LVIR_BOUNDS As Integer = 0

            Dim myrect As RECT
            Dim lvitem As ListViewItem = listView1.GetItemAt(pt.X, pt.Y)
            If lvitem Is Nothing AndAlso listView1.SelectedItems.Count > 0 Then
                lvitem = listView1.SelectedItems(0)
            End If
            Dim intLVSubItemIndex As Integer = -1
            Dim LVSubItem As ListViewItem.ListViewSubItem = Nothing

            If Not (lvitem Is Nothing) Then
                Dim intSendMessage As Integer
                Dim i As Integer
                lvitem.UseItemStyleForSubItems = False
                For i = 1 To lvitem.SubItems.Count - 1
                    LVSubItem = lvitem.SubItems(i)
                    myrect = New RECT
                    myrect.Top = i
                    myrect.Left = LVIR_BOUNDS
                    intSendMessage = SendMessage(listView1.Handle, LVM_GETSUBITEMRECT, lvitem.Index, myrect)
                    If pt.X < myrect.Left Then
                        LVSubItem = lvitem.SubItems(0)
                        LVSubItem.ForeColor = Color.Red
                        intLVSubItemIndex = 0
                        TextBox1.Text = LVSubItem.Text
                        Exit For
                    ElseIf pt.X >= myrect.Left And pt.X <= myrect.Right Then
                        intLVSubItemIndex = i
                        LVSubItem.ForeColor = Color.Orange
                        TextBox1.Text = LVSubItem.Text
                        Exit For
                        LVSubItem = Nothing
                    End If
                Next i
            End If
            If LVSubItem Is Nothing OrElse lvitem Is Nothing Then
                intLVSubItemIndex = -1
            End If
            Return intLVSubItemIndex
        End Function

    End Class

    Author Comment

    Thanks for the suggestion however the SubItem I am looking for is actually hidden from view (colWidth = 0) so I dont think your solution will apply to my situation. Sorry, I should have been clearer earlier.

    Without getting too into it, I have inherited some code whereby the previous developer had a listview to display a dataTable.  This dev implemented column sorting on the listview, however any selection of the listview for action (ie delete) uses the listview selected index and passes that to the function which does the delete.  the Delete function uses the listview index to lookup the record ID in the backend Datatable and then performs the action.  Works great if the listview is unsorted as the indexes will line up, unfortunately ppl want the sort feature.  

    I thought the easiest fix was to query the listview for the ID (btw, this is not always limited to one ID, it references multiple foreign keys that i need to perform action on depending on user input) which is added during population with a column width of 0.

    Thank you

    LVL 96

    Accepted Solution

    Try something like this:

      Public Function GetListViewSubItem(ByVal view As ListView, ByVal index As Integer, ByVal columnName As String) As ListViewItem.ListViewSubItem

        Dim item As ListViewItem = view.Items(index)

        For columnIndex As Integer = 0 To view.Columns.Count - 1
          Dim column As ColumnHeader = view.Columns(columnIndex)
          If column.Text.ToLower() = columnName.ToLower() Then
            Return item.SubItems(columnIndex)
          End If

        Next columnIndex

        Return Nothing

      End Function


    Author Comment

    Thank You Kindly. It seems so logical now.

    Featured Post

    Highfive + Dolby Voice = No More Audio Complaints!

    Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

    Join & Write a Comment

    The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (…
    If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
    To add imagery to an HTML email signature, you have two options available to you. You can either add a logo/image by embedding it directly into the signature or hosting it externally and linking to it. The vast majority of email clients display l…
    Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

    732 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

    Need Help in Real-Time?

    Connect with top rated Experts

    17 Experts available now in Live!

    Get 1:1 Help Now