Click here to Skip to main content
15,886,067 members
Articles / Desktop Programming / Windows Forms
Article

Add Group Collapse Behavior on a Listview Control

Rate me:
Please Sign up or sign in to vote.
4.65/5 (25 votes)
26 Nov 2008CPOL 209.9K   7.7K   51   42
Group collapse behavior added to a listview control under Windows Vista

Introduction

ListView control is an important but complex control in the WinForm environment. Group behavior is added into this control, but unfortunately, we can't collapse or expand the group.

I'll show how to use some simple code to add collapse/expand behavior on the ListView control.

This is a sample image on Windows Vista and Windows Server 2008:

lvnormal.jpg

Default group without Collapse/Expand behavior

lvgroup.jpg

Group with Collapse/Expand behavior

Using the Code

  • Define ListView group struct wrapper:

    C#
    [StructLayout(LayoutKind.Sequential)] 
    public struct LVGROUP 
    { 
            public int cbSize; 
            public int mask; 
            [MarshalAs(UnmanagedType.LPTStr)] 
            public string pszHeader; 
            public int cchHeader; 
            [MarshalAs(UnmanagedType.LPTStr)] 
            public string pszFooter; 
            public int cchFooter; 
            public int iGroupId; 
            public int stateMask; 
            public int state; 
            public int uAlign; 
    } 
  • Define the ENUM data:

    C#
    public enum GroupState 
    { 
            COLLAPSIBLE = 8, 
            COLLAPSED = 1, 
            EXPANDED = 0 
    } 
  • Interop for SendMessage function:

    C#
    [DllImport("user32.dll")] 
    static extern int SendMessage
    	(IntPtr window, int message, int wParam, IntPtr lParam);
  • Kernel method to set collapse/expand behavior on the ListView group:

    C#
    private void SetGroupCollapse(GroupState state)
    {
            for (int i = 0; i <= aoc.Groups.Count; i++){
                    LVGROUP group = new LVGROUP();
                    group.cbSize = Marshal.SizeOf(group);
                    group.state = (int)state; // LVGS_COLLAPSIBLE 
                    group.mask = 4; // LVGF_STATE 
                    group.iGroupId = i;
                    IntPtr ip = IntPtr.Zero;
                    try{
                            ip = Marshal.AllocHGlobal(group.cbSize);
                            Marshal.StructureToPtr(group, ip, true);
                            SendMessage(aoc.Handle, 0x1000 + 147, i, ip); // #define
                            LVM_SETGROUPINFO (LVM_FIRST + 147) 
                    }
                    catch (Exception ex){
                            System.Diagnostics.Trace.WriteLine
    			(ex.Message + Environment.NewLine + ex.StackTrace);
                    }
                    finally{
                            if (null != ip) Marshal.FreeHGlobal(ip);
                    }
           }
    } 

Points of Interest

C++
#define LVM_SETGROUPINFO (LVM_FIRST + 147)
#define ListView_SetGroupInfo(hwnd, iGroupId, pgrp) \
SNDMSG((hwnd), LVM_SETGROUPINFO, (WPARAM)(iGroupId), (LPARAM)(pgrp)) 

The above is the definition from SDK file: commctrl.h.

Limitations

  • In the current version, the rightmost collapse/expand icon doesn't work. :(
  • The collapse/expand behavior only exist in Windows Vista and Win2k8 systems.

History

  • 27th November, 2008: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
China China
I love C#.
I love using windbg to help customers solve the performance issues.

Comments and Discussions

 
QuestionGroup header font is blue and small Pin
Member 84279656-Jan-21 16:40
Member 84279656-Jan-21 16:40 
BugCrash on Windows 10 64-bit Pin
Real Anon User27-Jan-20 18:24
Real Anon User27-Jan-20 18:24 
QuestionAlign collapse/expand icon to the left Pin
HKe197219-Aug-15 5:55
HKe197219-Aug-15 5:55 
BugThere is a bug... Pin
Mikro_12317-Dec-13 21:47
Mikro_12317-Dec-13 21:47 
QuestionFixing click on collapse icon / Make it run on 32bit Pin
Ray K23-Sep-12 5:58
Ray K23-Sep-12 5:58 
AnswerRe: Fixing click on collapse icon / Make it run on 32bit Pin
Andira Muttakim29-Dec-12 4:57
professionalAndira Muttakim29-Dec-12 4:57 
GeneralRe: Fixing click on collapse icon / Make it run on 32bit Pin
Ray K27-Jan-13 6:38
Ray K27-Jan-13 6:38 
GeneralRe: Fixing click on collapse icon / Make it run on 32bit Pin
Ed Gadziemski18-Oct-14 18:41
professionalEd Gadziemski18-Oct-14 18:41 
AnswerRe: Fixing click on collapse icon / Make it run on 32bit Pin
Flanter30-May-13 15:38
Flanter30-May-13 15:38 
GeneralRe: Fixing click on collapse icon / Make it run on 32bit Pin
Ray K16-Jul-14 9:49
Ray K16-Jul-14 9:49 
QuestionButton from the group bar Pin
Member 865897530-Jul-12 21:33
Member 865897530-Jul-12 21:33 
QuestionCollapse/Expand is not working when you open the MainForm from another Form Pin
msiddu30-Jul-12 19:23
msiddu30-Jul-12 19:23 
AnswerRe: Collapse/Expand is not working when you open the MainForm from another Form Pin
Mikro_12317-Dec-13 22:00
Mikro_12317-Dec-13 22:00 
QuestionDoesn't work Pin
heavylifting18-May-12 8:13
heavylifting18-May-12 8:13 
AnswerRe: Doesn't work Pin
heavylifting18-May-12 8:16
heavylifting18-May-12 8:16 
GeneralRe: Doesn't work Pin
Shargon_8520-Oct-14 21:41
Shargon_8520-Oct-14 21:41 
Use this class for x86 and x64

C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode), Description("LVGROUP StructureUsed to set and retrieve groups.")]
    internal class LVGROUP
    {
        /// <summary>
        /// Size of this structure, in bytes.
        /// </summary>
        [Description("Size of this structure, in bytes.")]
        public int CbSize = Marshal.SizeOf(typeof(LVGROUP));

        /// <summary>
        /// Mask that specifies which members of the structure are valid input. One or more of the following values:LVGF_NONENo other items are valid.
        /// </summary>
        [Description("Mask that specifies which members of the structure are valid input. One or more of the following values:LVGF_NONE No other items are valid.")]
        public int Mask;

        /// <summary>
        /// Pointer to a null-terminated string that contains the header text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the header text.
        /// </summary>
        [Description("Pointer to a null-terminated string that contains the header text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the header text.")]
        [MarshalAs(UnmanagedType.LPWStr)]
        public string PszHeader;

        /// <summary>
        /// Size in TCHARs of the buffer pointed to by the pszHeader member. If the structure is not receiving information about a group, this member is ignored.
        /// </summary>
        [Description("Size in TCHARs of the buffer pointed to by the pszHeader member. If the structure is not receiving information about a group, this member is ignored.")]
        public int CchHeader;

        /// <summary>
        /// Pointer to a null-terminated string that contains the footer text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the footer text.
        /// </summary>
        [Description("Pointer to a null-terminated string that contains the footer text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the footer text.")]
        [MarshalAs(UnmanagedType.LPWStr)]
        public string PszFooter;

        /// <summary>
        /// Size in TCHARs of the buffer pointed to by the pszFooter member. If the structure is not receiving information about a group, this member is ignored.
        /// </summary>
        [Description("Size in TCHARs of the buffer pointed to by the pszFooter member. If the structure is not receiving information about a group, this member is ignored.")]
        public int CchFooter;

        /// <summary>
        /// ID of the group.
        /// </summary>
        [Description("ID of the group.")]
        public int IGroupId;

        /// <summary>
        /// Mask used with LVM_GETGROUPINFO (Microsoft Windows XP and Windows Vista) and LVM_SETGROUPINFO (Windows Vista only) to specify which flags in the state value are being retrieved or set.
        /// </summary>
        [Description("Mask used with LVM_GETGROUPINFO (Microsoft Windows XP and Windows Vista) and LVM_SETGROUPINFO (Windows Vista only) to specify which flags in the state value are being retrieved or set.")]
        public int StateMask;

        /// <summary>
        /// Flag that can have one of the following values:LVGS_NORMALGroups are expanded, the group name is displayed, and all items in the group are displayed.
        /// </summary>
        [Description("Flag that can have one of the following values:LVGS_NORMAL Groups are expanded, the group name is displayed, and all items in the group are displayed.")]
        public int State;

        /// <summary>
        /// Indicates the alignment of the header or footer text for the group. It can have one or more of the following values. Use one of the header flags. Footer flags are optional. Windows XP: Footer flags are reserved.LVGA_FOOTER_CENTERReserved.
        /// </summary>
        [Description("Indicates the alignment of the header or footer text for the group. It can have one or more of the following values. Use one of the header flags. Footer flags are optional. Windows XP: Footer flags are reserved.LVGA_FOOTER_CENTERReserved.")]
        public uint UAlign;

        /// <summary>
        /// Windows Vista. Pointer to a null-terminated string that contains the subtitle text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subtitle text. This element is drawn under the header text.
        /// </summary>
        [Description("Windows Vista. Pointer to a null-terminated string that contains the subtitle text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subtitle text. This element is drawn under the header text.")]
        public IntPtr PszSubtitle;

        /// <summary>
        /// Windows Vista. Size, in TCHARs, of the buffer pointed to by the pszSubtitle member. If the structure is not receiving information about a group, this member is ignored.
        /// </summary>
        [Description("Windows Vista. Size, in TCHARs, of the buffer pointed to by the pszSubtitle member. If the structure is not receiving information about a group, this member is ignored.")]
        public uint CchSubtitle;

        /// <summary>
        /// Windows Vista. Pointer to a null-terminated string that contains the text for a task link when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the task text. This item is drawn right-aligned opposite the header text. When clicked by the user, the task link generates an LVN_LINKCLICK notification.
        /// </summary>
        [Description("Windows Vista. Pointer to a null-terminated string that contains the text for a task link when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the task text. This item is drawn right-aligned opposite the header text. When clicked by the user, the task link generates an LVN_LINKCLICK notification.")]
        [MarshalAs(UnmanagedType.LPWStr)]
        public string PszTask;

        /// <summary>
        /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszTask member. If the structure is not receiving information about a group, this member is ignored.
        /// </summary>
        [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszTask member. If the structure is not receiving information about a group, this member is ignored.")]
        public uint CchTask;

        /// <summary>
        /// Windows Vista. Pointer to a null-terminated string that contains the top description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the top description text. This item is drawn opposite the title image when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER.
        /// </summary>
        [Description("Windows Vista. Pointer to a null-terminated string that contains the top description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the top description text. This item is drawn opposite the title image when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER.")]
        [MarshalAs(UnmanagedType.LPWStr)]
        public string PszDescriptionTop;

        /// <summary>
        /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionTop member. If the structure is not receiving information about a group, this member is ignored.
        /// </summary>
        [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionTop member. If the structure is not receiving information about a group, this member is ignored.")]
        public uint CchDescriptionTop;

        /// <summary>
        /// Windows Vista. Pointer to a null-terminated string that contains the bottom description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the bottom description text. This item is drawn under the top description text when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER.
        /// </summary>
        [Description("Windows Vista. Pointer to a null-terminated string that contains the bottom description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the bottom description text. This item is drawn under the top description text when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER.")]
        [MarshalAs(UnmanagedType.LPWStr)]
        public string PszDescriptionBottom;

        /// <summary>
        /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionBottom member. If the structure is not receiving information about a group, this member is ignored.
        /// </summary>
        [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionBottom member. If the structure is not receiving information about a group, this member is ignored.")]
        public uint CchDescriptionBottom;

        /// <summary>
        /// Windows Vista. Index of the title image in the control imagelist.
        /// </summary>
        [Description("Windows Vista. Index of the title image in the control imagelist.")]
        public int ITitleImage;

        /// <summary>
        /// Windows Vista. Index of the extended image in the control imagelist.
        /// </summary>
        [Description("Windows Vista. Index of the extended image in the control imagelist.")]
        public int IExtendedImage;

        /// <summary>
        /// Windows Vista. Read-only.
        /// </summary>
        [Description("Windows Vista. Read-only.")]
        public int IFirstItem;

        /// <summary>
        /// Windows Vista. Read-only in non-owner data mode.
        /// </summary>
        [Description("Windows Vista. Read-only in non-owner data mode.")]
        public IntPtr CItems;

        /// <summary>
        /// Windows Vista. NULL if group is not a subset. Pointer to a null-terminated string that contains the subset title text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subset title text.
        /// </summary>
        [Description("Windows Vista. NULL if group is not a subset. Pointer to a null-terminated string that contains the subset title text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subset title text.")]
        public IntPtr PszSubsetTitle;

        /// <summary>
        /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszSubsetTitle member. If the structure is not receiving information about a group, this member is ignored.
        /// </summary>
        [Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszSubsetTitle member. If the structure is not receiving information about a group, this member is ignored.")]
        public IntPtr CchSubsetTitle;

        public override string ToString()
        {
            return ("LVGROUP: header = " + this.PszHeader.ToString() + ", iGroupId = " + this.IGroupId.ToString(System.Globalization.CultureInfo.InvariantCulture));
        }
    }

GeneralRe: Doesn't work Pin
Franc Morales28-Oct-16 12:25
Franc Morales28-Oct-16 12:25 
GeneralRepaint problem on Vista/Win7 [modified] Pin
ZhuJinYong26-May-11 18:01
ZhuJinYong26-May-11 18:01 
GeneralMy vote of 5 Pin
ChewsHumans21-Oct-10 11:48
ChewsHumans21-Oct-10 11:48 
GeneralMy vote of 3 Pin
o.olll12-Aug-10 20:36
o.olll12-Aug-10 20:36 
GeneralCorrections Pin
imess18-Jan-10 10:35
imess18-Jan-10 10:35 
GeneralRe: Corrections Pin
ChristiaanJ11-Feb-10 5:58
ChristiaanJ11-Feb-10 5:58 
GeneralMy vote of 1 Pin
ts2224-Jul-09 10:25
ts2224-Jul-09 10:25 
GeneralRe: My vote of 1 Pin
Scott Dorman15-Sep-09 5:26
professionalScott Dorman15-Sep-09 5:26 
Generalgetting and setting the correct Group Id Pin
Paw Jershauge18-May-09 20:37
Paw Jershauge18-May-09 20:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.