PRB: Cannot Assign Images to a ColumnHeader Control in a Windows Forms ListView Control Using Visual Basic .NET (316202)



The information in this article applies to:

  • Microsoft .NET Framework 1.1
  • Microsoft .NET Framework 1.0
  • Microsoft Visual Basic .NET (2003)
  • Microsoft Visual Basic .NET (2002)

This article was previously published under Q316202
For a Microsoft Visual C# .NET version of this article, see 314933.

SYMPTOMS

When you attempt to assign images to a ColumnHeader control in a Windows Forms ListView control, the operation is unsuccessful.

CAUSE

This behavior occurs because the .NET implementation of the System.Windows.Forms.ColumnHeader class does not allow you to assign an image to the ColumnHeader control. You can assign only text to a ColumnHeader control.

RESOLUTION

To work around this issue in a .NET Windows Forms application, use Interop Services to send messages to the underlying Win32 ListView control to direct it to add the images to specific columns.

MORE INFORMATION

A ColumnHeader control is an item in a Windows Forms ListView control that contains heading text. You can use the Add method of the ListView.ColumnHeaderCollection class to add ColumnHeader objects to a ListView control. Because this class does not accommodate images, you can use Interop Services in a .NET Windows Forms application to add the images.

The following code sample demonstrates how to:
  • Send an LVM_GETHEADER message to the Windows Forms ListView control to obtain the ColumnHeader object.
  • Send an HDM_SETIMAGELIST message to the ColumnHeader control to set the image list that you want.
  • Fill out an LVCOLUMN structure and send it to the ListView control through an LVM_SETCOLUMN message to add an image from the image list to one of the columns.

Step-by-Step Example

  1. Start Microsoft Visual Studio .NET, and then create a new Windows Application in Visual Basic .NET. Form1 is added to the project by default.
  2. On Form1, add a ListView control, a Button control, and an ImageList control.

    Their default names are ListView1, Button1, and ImageList1 respectively.
  3. In the properties of ImageList1, click the ellipsis button (...) of the Images property, and then add two images to the control.
  4. In the code window of Form1.vb, add the following statement at the very top so that it is the first line of code:
    Imports System.Runtime.InteropServices
    					
  5. In the Form1 class, after the Inherits statement, copy and paste the following code:
    Public Const LVM_GETHEADER = 4127
    Public Const HDM_SETIMAGELIST = 4616
    Public Const LVM_SETCOLUMN = 4122
    Public Const LVCF_FMT = 1
    Public Const LVCF_IMAGE = 16
    Public Const LVCFMT_IMAGE = 2048
    
    
    'Define the LVCOLUMN for use with Interop.
    <StructLayout(LayoutKind.Sequential, pack:=8, CharSet:=CharSet.Auto)> _
    Structure LVCOLUMN
         Dim mask As Integer
         Dim fmt As Integer
         Dim cx As Integer
         Dim pszText As IntPtr
         Dim cchTextMax As Integer
         Dim iSubItem As Integer
         Dim iImage As Integer
         Dim iOrder As Integer
    End Structure
    
    'Declare two overloaded SendMessage functions. The
    'difference is in the last parameter.
    <DllImport("User32.dll")> _
    Public Overloads Shared Function SendMessage _
        (ByVal hWnd As IntPtr, ByVal Msg As Integer, _
         ByVal wParam As Integer, ByVal lParam As Integer) As IntPtr
    End Function
    
    <DllImport("User32", CharSet:=CharSet.Auto)> _
    Public Overloads Shared Function SendMessage _
        (ByVal hWnd As IntPtr, ByVal msg As Integer, _
         ByVal wParam As Integer, ByRef lParam As LVCOLUMN) As IntPtr
    End Function
    					
  6. In the Form1_Load event, copy and paste the following code:
    ListView1.View = View.Details
    ListView1.Columns.Add("Column 0", 60, HorizontalAlignment.Left)
    ListView1.Columns.Add("Column 1", 60, HorizontalAlignment.Left)
    					
  7. In the Button1_Click event, copy and paste the following code:
    Dim hwnd As IntPtr
    Dim lret As IntPtr
    Dim i As Integer
    
    'Assign the ImageList to the header control.
    'The header control includes all columns.
    'Get a handle to the header control.
    hwnd = SendMessage(ListView1.Handle, LVM_GETHEADER, 0, 0)
    
    'Add the ImageList to the header control.
    lret = SendMessage(hwnd, HDM_SETIMAGELIST, 0, (ImageList1.Handle).ToInt32)
    
    'The code to follow uses successive images in the ImageList to loop  'through all columns and place successive columns in the ColumnHeader.
    'This code uses LVCOLUMN to define alignment. By using LVCOLUMN here, 
    'you reset the alignment if it was defined in the designer. 
    'If you need to set the alignment, you must change the code below to set it here.
    For i = 0 To ListView1.Columns.Count - 1
          'Use the LVM_SETCOLUMN message to set the column's image index. 
          Dim col As LVCOLUMN
    
          col.mask = LVCF_FMT Or LVCF_IMAGE
          col.fmt = LVCFMT_IMAGE
          'The image to use from the Image List.
          col.iImage = i
          col.cchTextMax = 0
          col.cx = 0
          col.iOrder = 0
          col.iSubItem = 0
          col.pszText = IntPtr.op_Explicit(0)
          'Send the LVM_SETCOLUMN message.
          'The column to which you are assigning the image is defined in the third parameter.
          lret = SendMessage(ListView1.Handle, LVM_SETCOLUMN, i, col)
    Next
    					
  8. Press the F5 key to run the application. Click Button1, and notice that an image is added to each column header.

Modification Type:MajorLast Reviewed:3/24/2004
Keywords:kbWindowsForms kbListView kbCtrl kbprb KB316202