Link to home
Start Free TrialLog in
Avatar of QuinnB74
QuinnB74

asked on

Access ListView SubItem Text by Column Header

Hi,

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
Avatar of Howard Cantrell
Howard Cantrell
Flag of United States of America image

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()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        '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
                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.
    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.SuspendLayout()
        '
        'ListView1
        '
        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
        '
        'Label1
        '
        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"
        '
        'TextBox1
        '
        Me.TextBox1.Location = New System.Drawing.Point(212, 220)
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.TabIndex = 2
        Me.TextBox1.Text = "TextBox1"
        '
        'frmClickSubItem
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(478, 244)
        Me.Controls.Add(Me.TextBox1)
        Me.Controls.Add(Me.Label1)
        Me.Controls.Add(Me.ListView1)
        Me.Name = "frmClickSubItem"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    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)
            ListView1.Items.Add(lvi)
        Next

        For Each ch In ListView1.Columns
            ch.Width = -2
        Next
    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
                Else
                    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
Avatar of QuinnB74
QuinnB74

ASKER

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
Q

ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank You Kindly. It seems so logical now.