Winform控件ListView实现分组展开折叠

B站的直播分类中有分一个二级的子分组,然后我这边的 ListView 窗口比较小,为了方便快速找到需要的分组,希望可以对 ListView 的一级分组进行折叠和展开。

Winform控件ListView实现分组展开折叠
默认控件是没有这个功能的,以下是一个非k I 5 - J ]常棒的控件继承类,到时候双击分组栏或者点击右侧按钮就可以了。

using System;
using System.Collections.Genq ` 9 8 c H T w }eric;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.InteroO W _ w V } t h KpSe/ , orvices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
nai ^ , m W s X G 8mespaci . We TelePlayer.Mic
{
public class ListViewExtended : ListView
{
prb X l p ` Jivate const int LVM_FIRST = 0x& ^ r1000;                    // ListView messages
private const int LVM_SETGROUPINFO = (LVM_FIRST + 147);  // ListView m^ # @ S (essages Setinfo on Group
private const int WM_LBUTTONUP = 0xR Y z U g Q o _0202;                 // Windows message left button
private] : 6 delegate void CallBackSetGroupState(ListViewGroup lstvwgrp, Li* } M - C $ 3 : TstViewGroupStatM c B [e state);
private df * 1 H a s pelegate void CallbackSetGroup` ( ( : f ~ v m EString(ListVG , 8 Q 9iewGroup lstvwgrp, string value);
/// <summary>
/// Sends thS G Z l ) : D O 1e specT 3 Fified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has prD b m O  @ocessed the message.
/// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage functi% ? - 7 ~ W [ &on. To post a message to a thread's mesq T x .sage queue and return immediately,A } z 4 use the PostMessage or PostThreadMessage function1 d .  {.
/// </summaryM X 5 R>
/// <param name="hWnd">
/// [in] Handle to the window whosen G [ v d O X window proc{ n Cedure will receive the message.
/// If this parameter is HWND_BROADCAST, the message ist N 9 A ` : S # sent to all top-level windows in the system, including disM % u nabled or invisible unowned windows, overlapped windows, and pop-upa P Q ^ D 9 windows; but the message is not sent to child windows.
/// Microsoft Wz  $ Q { b k V Iindows Vista and later. Message sending is subject to User Interface Privilege Isolation (UIPI). The thread of a process can send mess# h G #ages only to message queues of threads in processesr ` R a N P t m of lesser or equal inte_ C & k dgrity level.
/// </paraR D 9 h h m>
/// <paraE { r C . 3m name="uMsg">[in] Specifies the message to be sent.</parab G r J Z M xm>
/// <param name="wParam">[in] Specifies additional messa; ( k - Z s = +ge-specific information.</param>
/// <param name="lParam">m g ; ; ~ c `[in] Type of LVGROUP, Specifies additional message-specij , ;fic information.</param>
///S k H f K } s [ <returns>
/// Microsoft Windows Vista and later. When a message is blockedO R v 6 } 3 R : x by UIPI the last error, retrieved with GetLastError, is set to 5 (acx N L 3 Y Ccess denied).
/// Applications that need to communicate using HWND_BROADCASh N  Y `T sho@ - S m $  % .uld use the RegisterWindowMessage functiR k 1 E u * d I von to obtain a unique message for inter-application communication.
/// The system only does marsJ J dhalling for syst@ m j + 2 (em messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshl # R o F F k X falling.
/// If thu ) $ w c Ze specified window was created by the calling thread, the window procedure is called immediC ^ M ; 7 b Zately as a subroZ E yutine. If the specified window was created by a differenH 0 M U ; ? h A jt thread, the syS t F u l c j ;stem switches to that thread and calls the appropriaW S C ate window procedure. Messages sent betweens * K 1 . R g & & threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiv2 ~ j _ & Eing thread processes the message. However, the sending thread will process incoming nonqueued messages while waiting for its message to be processed. To prev] c L s F # | z 0ent this, use SendMessageTimeout with SMTO_BLOCK set. For morew e t . 1 infort j ]mation on nonqueued messages, see Nonqueued Messages.
/// Windows 95/98/Me: SendMessageW is supported by the Microsoft LP 5 @ R %ayer for Unicode (MSLU). To use this, you must add certain files to your application, as o( s z } { 1 { T [utlined in Microsoft Layer for Unicode on Windows 95/98/Me Systems.
/// </returns>
[DllImpo! W G nrt("Us1 ( +er32.dll"), Description("Sends the speciX z Ffied message to a window or windows. The SendMessage function ca; ! C & u A jlls the wind` F 7 ^ zow procedure for the specified window and does not return until the window procedure has processed the messagr N U S K 9e.? ^ | b F - To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage functs Q k U Z S ion. To post a message to a thread's messag9 E ve queue av  I Z  o ` dnd return immediately, use the PostMessage or PostThreadMessage function.")]D Z L 0 K /
priva+ K zte s: . V ? $ ctatic extern int SendMessage4 p B , A(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
privateK 4 F Q [ staticP 4 | b 1 n q int? GetGroupID(ListViewGroup lstvwgrp)
{
int? rtnval = nup ~ g 0 G rll;
Type GrpTp = lstvwgrp.GetType();
if (GrpTp != null)
{
PropertyInfo piv ) D = GrpTp.GetProperty("IDS T g 7 c *", BindingFlags.NonPublic | BindingFY + M R V V Rlags.Instance);
if (pi != nul7 v y ` E % cl)
{
object tmprtnval = pi.GetValue(lstvw( R % 1grp0 z b, null);
if (tmprtnval != null)
{
rtnval = tmprtd j ! m / H ; 7 Mnval as int?;
}
}
}
return rtnval;
}
private static vo) c ; ( ` Yid setGrpState(Lis6 T E ZtViewGroup lstc D ) 7 # pvwgrp, ListViewGroupState state)
{
if (Envb V 9 r ironment.OSVersion.Version.Major < 6)   //Only Vista and forward allows collaps of ListViewGroups
return;
if (lstvwgrp == null || lstvwgrp.% s | & 4 L sListView == null)
return;
if (lstvwgrp.ListView.InvokeRequired)
ls& @ ^ 0 e b Ktvwgrp.ListView.Invoke(new CallBackSetGroupState(setGrpSM 4 B ( 9 @ 7 g dtate), lstvwgrp, st/ | L kate);
else
{
int? GrpId = GetGroupID(lstvwgrp);
int gIndex = lstvwgrp.ListVM 6 B % - P @ 2 Xiew.Gr/ ~ I 2oups.IndexOf(lstvwgrp);
LVGROUP group = new LVGROUP();
group.CbSize = MarshU D ] 7 al.SizeOf(group);
group.State = state;
group.Mask =L ^ e O s ListViewGroupMask.State;
IntPtr ip = Marshal.AllocHGlobal(group.CbSize);
Marshal.Str0  d s 1 9uctureToPp E Y x 9tr(group, ip, false);
if (GrpId != null)
{
group.IGroupId = GrH n $pId.Value;
SendMessage(lst( r I ` M *vwgrp.ListView.HaR n Y 2 Z =ndle, LVM_SP s B _ X y  WETGROUPINFO,A  e GrpId.Value, ip);
SendMessage(lstvwgrp.ListView.Handle, LVM_SETGROUPINFO, GrpId.Value, ip);
}
else
{
group.IGroupId = gIndex;
SendMessage(lstvwgrp.ListView.Handle, LVMH H 8 ] 3 H_SR 9 3 v R RETGROUPINFO, gIndex, ip);
SendMessage(lsK h g p P : a G (tvwgrp.ListView.HI  c # andle, LVM_SETGROUPINFO, gIndex, ip);
}
lstvw[ M j O N # ugrp.ListView.Refresh();
}
}
pD V 3ublic void SetGroupState(ListViewGroupS@ 4 | utate state)
{
foreach (ListViewGroup lvg in this.Groups)
setGrpState(lvg, state);
}
protected override void WndProc(ref Men T 5 * X Q K  yssage m)
{
if (m.M@ E L +sg == WM_L! b H 4 vBUTTONUP)
base.DefWndProc(ref m);
base.WndProc(ref m);
}
}
/// <summary>
/// LVGROUP StructureUsed to set and retrieve groups.
/// </summary>
/// <0 e E 0example>
/// LVGROUP myLVGROUP = new LVGROUP();
/// myLVGROUP.CbS z g 7 u C  Wize// is of manag% H F @ jed type uint
/// myLVGROUP.Mask// is of managed typb | h 8 Re uint
/// myLVGROU- D ! P 1 n KP.PszHeader// i& w A 0 ) ] ss of managedV a W G 3 M B i type string
/// myLVGROUP.CchHeader//k a ^ l T ^ s ~ is of managed type int
/// myLVGROUP.PszFooter// isJ / ^ # a W ] h y of managed type string
/// myLVGROUP.CchFooter// is of managed type int
///v q $ G myLVGROUP.IGroupId// is of managed type int
/// myLVGROUP.StateMask// is of managed typeb h a y . uintF / ! & #
/// myLVGROUP.State// is of managH ^ G [ O T b E hed type uint
/// myLVGROUP.UAlign// is of managed type uint
/// myLVGROUP.PF T l m w - NszSubtitle// is of managed type IntPtr
/// myLVGROUP.CchSubtitle// is of managed type uint
/// myLVGROUP.PszTask//f z d 9 ; ; T [ isG S L I v E S 8 Q of managed type strinm ! : / f 0 # Jg
/// myLVGROUP.CchTask// is of managed tyj * xpel H w uint
/// myLVGROUP.PszDescriptionTop// is of maR L - * Nnaged type string
/// myLVGROUP.CchDescriptionTop// is of managed type uii d 6nt1 t G
/// myLVGROUP.PszDescriptiH y @ w % o x yonBottom// is of managed type string
/// myLVGROUP.CchDescriptionBottom// is of man 4 ( $ v Vnaged type uint
/// myLVGROUP.ITitleImage// is of managed type int
/// myL7 Y O k o dVGROUP.IExtendedImage// is of managed ty( u n e { q c k +pe int
/// mP ? n 3 uyLVGROUP.IFirstIt& = : n N em// is of managed` 8 : [ P type int
/// myLVGROUP.CItems// is of managed type IntPt! Q M 0 $ T Mr
/// myLVGR- i ] x p |OUP.PszSubsetTitle// is of managed type IntPtr
/// myLVGROUP.CchSubsetTio ] } C f 5 ~tle//+ ; 8 1 H % } is of managed type Int6 R 0 C l [ o 7 FPtr
/// </example,  H / ) x - i y>
/// <remarks>
/// The LVGROUP str9 F S s X 5ucture was created by Paw Jershauge
/// CreateN u 1 [d: Jan. 2008.
/// The LVGROUP structure code is based on information fC N j x @ d Z Brom MicrosoftK ; 5 z * !'s MSDN2 website.
/// The struv P { j $ & `cture is generated via an automated converter and is as is.
/// Thn j X O r 6 G f De structure may or may not hold errors inside the code, so use at own risk 9 M C o X.
/// Refe`  )rs x g Y [ 9 J uence url: http://J v X R V e m }msdn.microsoft.com/en-us/library/bb774769(VSn W ; o $ j G.85).aspx
/// </remarks>
[StructLayout(Layo3 o { p ]utKind.Sequential, CharSet = CharSet.Un[ e f l e O % 4 Bicode), Description("LVGROUP StructureUset a ^d to set and retrieve groups.")]
public st 3 - L t M , +truct LVGROUP
{
/// <summary>
/// Size of this structure, in bytes.
/// </summary>
[Description("Size of this structure, in bytes.")]
public int CbT 4 d USize;
/// <summary>
/// M_ m ,ask` w Q } 6 ! that specifies which mem~ t r r 9 : b Xbers of the structure are valid input. One or more of the following values:LVGF_NONENo other items are valid.
/S N 7 d y m// </summary>
[Description("Mask that specifies which members of the structure are valid input. One or more of th~ 5 ] w % j $e following values:LVGF_NONE No other items are valid.")]
public ListViewGroupMask Mask;
/// <summary>
/// Pointer to a null-terminated stq Z 1 G % i t Lr ; s W T { 9 Ring 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 wheK o ? E ) c 4 ~ n item information is being set.] i % ~ [ 0 O o If group information isi O : Q / d , being retrieved, this member specifieS $ } t ) Bs the address of the buffer that receives the header text.")]
[MarshalAs(Unmanage( | * )  ;dType.LPWStr)]
pubS M J - flic string PszHeader;
/// <summary>
/// Size in TCHARs of the buffer pointed to by q B ; ) Wy the pszHeader member. If the structure is not receiving information about a group, this membez ^ B $ ^ ? b 9 tr is ignored.
/// </summary>
[Description("Size in TCHAR9 C s ) Ds of the buffer pointed to by the pszHeader member. If the structure is not receiving information about a[ ] p 2 D o y group, this member is ignored.")]
public int Cck B v l ` 2 =hHea7 M 8 [ %der;
/// <summary>
/// Pointer to a null-terminated string that contains the footer text when item information is being set. If group information is beG p Ring retrieved1 p p X g H ,, this member specifies the address of the buffer that receives the footer text.
/// </su8 Y O 4 ; H / H 9mmary>
[Description("Pointer to a null-te% | U T - ? Y xrminated string that contains the footer tej M @ W ; ] 2 C hxt when item information is being set. If group informatil  a * Ron is being retrieved, this member specifies the address og p O R ^ M u Tf the buffer that receives the footer text.")]
[MarshalAs(UnmanagedType.LPWStr)]
public strinD + 2 p w h hg PszFooter;
/// <summary>
/// Size in TCHARs of the buffer pointed to by the pszFooter member. If the structure is not receiving informat@ B 4 h r K 2 v `ion about a group, this membI M S y Y [ P &er{ p ( O N is ignored.
/// </summary>
[Description("Size in TCHARs of the! + # -  L ~ o Y buffer pointed to by the pszFooter memk B x : 0ber. IZ l G = Gf the structure is not receiv3 K 3 F Q R U K _ing in-  H s T H q fformation about a groupQ y i u ., this member is ignored.")]
pub{ - i n 1 j 5 L Slic int CchFooter;
/// &la } , |t;summa= , V ! o M /ry>
/// ID of the group.
/// </summp M A ^ 5ary>
[Description("ID of the group.")]
pubq I f X k /lic int IGroupId;
/// <summary>
/// Mask used with LVM_GETGROUPINFOG m g i R 4 # (Micr: ( . v x .osoft Windows XP and Windows Vista) and LVM_SETGROUPINFO (6 D NWindows Vista only) to specify which flags in the state value are being retrieved or set.
/// </suw w Q # k _mmary>
[Description("Mask used with LVM_GETGROh A D [ U | mUPINFO (Microsoft Windo~ % - P )wT ; s  % x 8 j s XPo K h 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;
/// <su` Y e n e x 9 1mmary>
/// Flag that can ha} ` _ C cve one of the following values:LVGS_NORMALGroups are expanH l K tded, the group name io L G js displayed, and all items in the group1 , B  Z q p o & are displayed.
/// </summary>
[Description("Flag that can have one of the following values:LVGS_NORMAL Groups are expanded, the group name0 w H /  is displayed, and all items in the group are displayed.")]
public ListViewGroupState State;
/// <summary>
/// Indicates the alignment of the header or footer text for the groK m L k ? O Y Yup. It can have one or more of the fm X t ~ 0 Z e Z (ollowing values. Use one of the header flags. Fo% c 2 x ( g b M ,oter flags/ g t K m ^ ac c 0 H y F % Mre optional. Windows XP: Footer flags are reserved.LVGA_FOOTER_CENTERReserved.
/// </summary>
[Description("Indicates the7 r | alignment of the header or footer text for the group. It can had = $ fve one or~ H w ~ c * more ofn b c P u e th| n c 3e following values. Use one of the header flags. Footer flags are optional. Windows XP: Footer flags are reserved.LVGA_FOOTER_CENTERReserved= o U G o $ @.")]
public uint UAli + I , 3 e ngn;
/// <summary>
/// Windows Vista. Pointer to a null-terminated string that contains the subtitle ? 4 V g ; u ^ B text when item information is being set. If gro? V / b o ` Yup information is being retrieved, this member s{ w 9 ^ mpecifies 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-terG . Fminated string that contains the subtitle text when item{ a ( I information8 l F L K is being set. If group information is being retrieved, this member specif] ! M 3 C Ties the address of the buffer thaq F Jt receives the subtitle text. This element is drawn under the header text.")]
public IntPk ~ 4tr PszSubtitle;
/// <summary>
/// Wv m oindows Vista. Size, in TCHARs,^ ) E e f p  y of the buffer pointed to by the pszSubtitle m( Z I e h : R +ember. If th@ K S t :e 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 th: : ` X N *e pszSubtitle member. If the structure io k f j D is noV x i + p R ct receiving information about a group, this membY g % Per is ignored.")]
public uint CchSubtitle;
/// <summary>H _ U r d L | H N
/// Windows Vista. Pointer to a null-terminated string that conts a } rains the text for a task link when item iR c Znformation is being set. If group information i& 7 x G . p A e 6s being retrieved, this member specifies the address of the buffer that receives the tas$ K ~k 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-termina& d A s k xted string that contains the text for a task link when item information is being set. If group information is being retrieved/ F . d a A q - E, 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_x  v x F t Z ; 5LINKCLICK noQ k $ U , 9 tifio 3 ; } @catiI ) l I + +on.")]
[MarshalAs(UnmanagedType.LPWStr)]
public string PszTask;
/// <summary>
/// Windows Vista. Size in TCHARs of the buffe- } s * # D j *r pointed to b* e q % r &y the pszTask member. If the structure is not receiving information about a group, this member is i| Y pgnored.
/// </summary>
[Description("Windows Vista. Size in TCHARs of the buffer pointed to by the pszTask member. If the structu7 ` h . f F ! R dre is not receiving information about a groupb y P t 5 L, this member is it ` o xgnored.")]
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 spd 7 q [ecifies the address. = F # d I of the buffe, X - r that receiv{ 7 zes the top description text. This item is drawn opposite the title image when there is a title image, no ew z ? i L  uxtended image, and uAlign==LVGA_HEADER_CENTER.
/// </summary>
[Description("Windows Vista. Pointer to a null-terminated string that contains the to? 3 !p description text when item infok P - 1 . s t 5rmation is being set. If group infof h i , 2 { ^ M ermation is being retrieved, this member specifies the address of the buffer that recei] . u +ves the top description text. This iu $  { F I 8 Ktem is drawn opposite the title image when there is a titlJ 4 W ; ( ^ fe image, no extended image, and uAlign==LVGA_HEADE& A aR_CENTER.")]
[Marsha] + 3 | MlAs(UnmanagedType.LPWStr)]
public string PszDescriptionTop;
/// <summary>
/// Windows Vista.` K [ i N | u $ Size in TCHARs of the bup z ` @ H X Wffer pointed to by t& ? Y 8 L 4 ` ; )he pszDescriptionTop member. If the structure is not receiving information about a grouE G o Q 0 R o _ qp, this member is ignored.
/// </summary>
[Description("Windows Vista. Size in TCHARs of the buffer p4 t }ointed to by the pszDescriptionTop member. If the structure is not rem G a Y C S &ceiving information about a group, this member is ignored.")]
public uint CchDescriptio_ [ - jnTop;
/// <summary>
/// Windows Vista. Pointer$ G e F 6 c - o 3 to a nu= V h ,ll-tt X P T s B I terminated string that contains the bottom description text} 1 p f when ite{ o r m } 8 P Um information is being set. If grz $ M H i + houp informatio2 i . 1n is being retrieved, this member specifies the address ofP e c t the buffer that receives the bottom description text. This itemC $ 1 | F is drawn under the top description text when there is a title imZ = E zage, no extende1 p 2 0 Ld image, and uAlign==LVGA_HEADER_CENTER.
/// </su$ W X q i F mmmary>
[Description(; Y u E - A - S"Windows Vista. Pointer to a null-terminated string that coB . $ntains 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 bot[ # ) ; d gtom descriptioq G x 7n text. This item is drawnF B i J . u Z = under the top description text when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTE] e LR.")]
[MarshalAs(UnmanagedT* @ O Lype.LPWM 0 F d ZStr)]
public string PszDescriptionBottom;
/// <summar x  ? } m .y>
/// Windows Vista. Size in TCHAR0 } ] Ds of the buffer pointed to by the pszDescriptionBottom member. If the structure is not receiving information about a= ) , Q N p ~ { r group, this membe` _ a / Y ? D f Zr is ignored.
/// </summary>
[Description("Windows Viy q c X J P sta. Size in TCHARs of the buffer pointed t/ + - ;o by the pszDescri9 L X f k |ptionBottom member. If the structure is not receiving information about a group, this member is ignp / [ored.")]
public uint CchDeu 5 A Y ] k ] y MscriptionBottom;
/// <summary>
/// Windf & f h m aows Vista. Io ~ V Sndex of the title image in the control imagelist.
/// </summary>
[Description("Windows Vista. Index of the title image in the control imagelist.")]
public int I! } u E # x H @TitleImage;
/// <summary>
/// Windows Vist$ G [ i . C . Da. Index of the extended image in the co; u b Lntrol imagelist.
/// </e l ) [summary>
[Description("Windows Vista. Index of the extended image in the control imagelist.")]
public i| C x S [ ~ ` E nnt IExtendedImage;
/// <summary&gb ) ! 8t;
/// Windows V; [ H Rista. Read-only.
/// </summary&l R T V H Cgt;
[Description("Windows V` 5 ~ jistaZ + O W -. Read; V K 4 O-only.")]
public int IFirstItem;
/// <summary>
/// Windows Vista. Read-only in non-owner data mode.
/// </summary>
[Description("Windows Vista. Read-ob o |nly in non-owner data mode.")]
public IntPtr CItems;
/// <` z # E ] ksummary>
/// Windows Vista. NULLw ) / _ r ` if group) d C p 3 1 r 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 thR ~ W p & Bat receA | %ives the subsetR R J D Q - G title text.
/// </summary>6 4 . ` 3
[Descri+ k 1 2 Zption("Windows Vista. NULL if group is not a subset. Pointer to a null-terminated string that contains the subset title ten 1 I y Rxt when item information is being set. If group information is being retrieved, this memberT R _ ( U specifies t! + E ~he address of the buffer that receives the subset title text.")]
public IntPtr PszSubsetTitle;
/// <summary>
/// Windows Vista. SizT ^ x @ xe in TCHX B ( H } _ 8 X DARs of the buffer pointed to by the pszSubsetTitle member. If the s^ & c t l = - J ]tructure is not receiving information about a group, this member is ignored.
/// </summary>
[Description("Windows Vista. SC 8 P Uize ink o N W TCHARs of the buffer pointed to by the pszSubsetTitle member. If the structurd , x { e f m R se is not receiving information about a group, this member is ignored.")]
public IntPtr CchSubsetTitle;
}
public enum ListVi: E H c iewGroupM# Y g p Xask
{
None = 0x00000,
HeaM ; X N W ( Y Fder =r c B ; L 5 0x00001,
Footer = 0x00002,
State = 0x00004,
Align = 0x00008,~ r j _ u C
GroupId = 0x00010,
SubTitle = 0x00100,
Task = 0x00200,
DescriptionTop = 0x00400,
DescriptionBottom = 0x00800,
TitleImage = 0x01000,
ExtendedImage = 0x02000,
Items = 0x04000,
Subset = 0x08000,
SubsetItems = 0x10000
}
public enum ListViv i XewGroupState
{
/// <summary>
/// 分组处于展开状态, 并且显示分组名称,
/// 分组中的所有项目也同时可见。
/// </summaryS ; ~>
Normaw t %l = 0,
/// <summary>
/// 分组处于被折叠的状态。
/// </summary>G , ^ 5;
Collapsed = 1,
/// <summary>
/// 分组处L V s ] ) 1  X于被隐藏的状态。
/// <m X + 6;/summary>
Hidden = 2,
/// <summary>
/// 在6.00版本和Windows Vista下,不显+ * B R h z } p e示分组U L C u j g标题。
/// </summary>
N5 y _ m | C ;oHeader = 4,
/// <summary>
/// 在6.00版本和Windows Vis3 ( 4 z i N n . mta下,分组可以被折叠。
/// </summary>
Collapsible = 8,
/// <summary>
/// 在6.00版本和WindowF i ! i C  Z /s Vista下,分组E 2 L  h拥有键盘焦点。
/// </summary>
Focused = 16,
/// <summary>
/G D  m n / g // 在6.00版本和Windows Vista下,分组被选中。
/// &u G m T ; 1 Mlt;/summary>
Selected = 32,
/// <summary>
/// 在6.00版f ; p本和Windows Vista下,分组中只有一部分被显示出来。
/// </summary>
SubSeted = 64,
/// <summary>
/// 在6.00版本和Windows Vista下,分组S f g o F . % ; v的一部分项目拥有键盘焦点。
/// </summary>
SubSetLinkFoJ _ n S n : Pcused = 128,
}
}

如下效果就简单明了了。

Winform控件ListView实现分组展开折叠