PRB: Windows Forms TreeView Control Does Not Handle State Image Lists in Visual Basic .NET (315934)



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 Q315934
For a Microsoft Visual C# .NET version of this article, see 313134.

SYMPTOMS

The Windows Forms TreeView control displays a hierarchy of nodes that is similar to the way that Windows Explorer displays folders in the left pane. With the Windows Forms TreeView control, the application cannot use a State image list to display a State icon. The State icon appears to the left of the icon that is displayed for a node in the control. This behavior differs from the behavior of the underlying Win32 TreeView control.

RESOLUTION

The .NET Windows Forms application can use Interop services to direct the underlying Win32 TreeView control to display a State icon. To do this, the application can assign a value to each field in the TVITEM structure and send a TVM_SETITEM message to the underlying Win32 TreeView control through Interop services.

MORE INFORMATION

A Win32 TreeView control has two image lists that are associated with it:
  • Normal image list, which contains selected, nonselected, and overlay images for the items of a TreeView control.
  • State image list, which you can use to indicate application-defined item states. A State image is displayed to the left of an item's selected or nonselected image.
Because the Windows Forms TreeView control does not handle the State image list, follow these steps:
  1. Use Interop services to send a TVM_SETIMAGELIST message with the TVSIL_STATE flag to the underlying Win32 control to set the State image list.
  2. Send a TVM_SETITEM message to tell the control on which node to display a specific image from the image list. You must define the Win32 API function SendMessage to send these messages.
Because the TVM_SETIMAGELIST message and the TVM_SETITEM message require different parameters when they are sent to a TreeView control, you must overload the SendMessage function (as the following code shows).

This code demonstrates how to add a State image list to a Windows Forms TreeView control and how to display an image from the control on the root node.

Step-by-Step Example

  1. Start Microsoft Visual Studio .NET, and then create a new Windows Application using Visual Basic .NET. Form1 is added to the project by default.
  2. On Form1, add a TreeView, a Button, and an ImageList control. Their default names are TreeView1, Button1 and ImageList1 respectively.
  3. In the Properties of ImageList, click the ellipsis button (...)of the Images property, and then add at least two images. This is required for the sample to work.
  4. In the code window of Form1.vb, add the following statement as the first line of code:
    'Use Interop services
    Imports System.Runtime.InteropServices
    					
  5. Copy and paste the following code after the Inherits statement in Form1 class:
    Public Const TV_FIRST = 4352
    Public Const TVSIL_NORMAL = 0
    Public Const TVSIL_STATE = 2
    Public Const TVM_SETIMAGELIST = TV_FIRST + 9
    Public Const TVM_GETNEXTITEM = TV_FIRST + 10
    Public Const TVIF_HANDLE = 16
    Public Const TVIF_STATE = 8
    Public Const TVIF_IMAGE = 2
    Public Const TVIS_STATEIMAGEMASK = 61440
    Public Const TVM_SETITEM = TV_FIRST + 13
    Public Const TVGN_ROOT = 0
    
    
    'Use a sequential structure layout to define TVITEM for the TreeView control.
    <StructLayout(LayoutKind.Sequential, Pack:=8, CharSet:=CharSet.Auto)> _
    Public Structure TVITEM
        Dim mask As Integer
        Dim hItem As IntPtr
        Dim state As Integer
        Dim stateMask As Integer
        Dim pszText As IntPtr
        Dim cchTextMax As Integer
        Dim iImage As Integer
        Dim iSelectedImage As Integer
        Dim cChildren As Integer
        Dim lParam As IntPtr
    End Structure
    
    'Declare two overloaded SendMessage functions. The
    'difference is in the last parameter: one is ByVal and the
    ' other one is ByRef.
    <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 Integer
    End Function
    
    <DllImport("User32.dll", CharSet:=CharSet.Auto)> _
    Public Overloads Shared Function SendMessage _
        (ByVal hWnd As IntPtr, ByVal msg As Integer, _
        ByVal wParam As Integer, ByRef lParam As TVITEM) As Integer
    End Function
    					
  6. In the Form1_Load event, copy and paste the following code:
    TreeView1.Nodes.Add("Node1")
    TreeView1.Nodes.Add("Node2")
    					
  7. In the Button1_Click event, copy and paste the following code:
    Dim hWnd As IntPtr
    Dim hRoot As IntPtr
    Dim tvi As TVITEM
    Dim lRet As Integer
    
    hWnd = TreeView1.Handle
    'Send a TVM_SETIMAGELIST with TVSIL_STATE.
    lRet = SendMessage(hWnd, TVM_SETIMAGELIST, TVSIL_STATE, (ImageList1.Handle).ToInt32)
    'Get a handle to the top row
    hRoot = IntPtr.op_Explicit(SendMessage(hWnd, TVM_GETNEXTITEM, TVGN_ROOT, 0))
    'The following uses the TVM_SETITEM message to set the state 
    'of a given item. It uses the TVITEM structure.
    'tvi.mask: include TVIF_HANDLE and TVIF_STATE
    tvi.mask = TVIF_HANDLE Or TVIF_STATE
    'To use the state image, tvi.state cannot be 0.  
    'Setting it to 1 means to use the second image in the image list.
    tvi.state = 1
    'Left shift the bits by 12 to put information in bits 12 to 15.
    tvi.state = tvi.state * (2 ^ 12)
    'Set stateMask. -This is required to isolate state above.
    tvi.stateMask = TVIS_STATEIMAGEMASK
    'Set state for the root node.
    tvi.hItem = hRoot
    'Initialize the rest to zero.
    tvi.pszText = IntPtr.op_Explicit(0)
    tvi.cchTextMax = 0
    tvi.iImage = 0
    tvi.iSelectedImage = 0
    tvi.cChildren = 0
    tvi.lParam = IntPtr.op_Explicit(0)
    'Send the TVM_SETITEM message.
    lRet = SendMessage(hWnd, TVM_SETITEM, 0, tvi)
    					
  8. Press the F5 key to run the application. Click Button1 and notice that a state image is added to the root node.

Modification Type:MajorLast Reviewed:3/24/2004
Keywords:kbWindowsForms kbTreeView kbGDI kbCtrl kbprb KB315934 kbAudDeveloper