private void ExpandOrCollapse(bool collapse) { CheckControlEnabled(); // Check if item can be expanded or collapsed. bool isCollapsed = IsCollapsed(); if ((!collapse && !isCollapsed) || (collapse && isCollapsed)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } NativeMethods.LVGROUP group = new NativeMethods.LVGROUP(); group.Init(Marshal.SizeOf(typeof(NativeMethods.LVGROUP))); // Note: If we set group.mask to LVGF_GROUPID | LVGF_STATE, // SetGroupInfo() will fail. Setting LVGF_STATE alone works, however. group.mask = NativeMethods.LVGF_STATE; group.iGroupID = _groupID; group.stateMask = NativeMethods.LVGS_COLLAPSED; group.state = collapse ? NativeMethods.LVGS_COLLAPSED : 0; if (!XSendMessage.SetGroupInfo(_hwnd, group)) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } }
protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); if (CollapsibleGroups && Groups.Count > 0) { for (int i = 0; i < Groups.Count; i++) { NativeMethods.LVGROUP group = new NativeMethods.LVGROUP { cbSize = Marshal.SizeOf(typeof(NativeMethods.LVGROUP)), mask = NativeMethods.LVGF_GROUPID }; IntPtr Result = NativeMethods.SendMessage(Handle, NativeMethods.LVM_GETGROUPINFOBYINDEX, i, ref group); if (NativeMethods.NativeToBool(Result.ToInt32())) { int groupId = group.iGroupId; group = new NativeMethods.LVGROUP { cbSize = Marshal.SizeOf(group), state = NativeMethods.LVGS_COLLAPSIBLE, mask = NativeMethods.LVGF_STATE, iGroupId = groupId }; NativeMethods.SendMessage(Handle, NativeMethods.LVM_SETGROUPINFO, group.iGroupId, ref group); } } } }
public void SetGroupState(ListViewGroupState state) { if (!EnvUtils.RunningOnWindows() || Environment.OSVersion.Version.Major < 6) { // Only Vista and forward // allows collapse of ListViewGroups return; } foreach (ListViewGroup lvg in Groups) { SetGrpState(lvg); } Refresh(); return; void SetGrpState(ListViewGroup lstvwgrp) { int groupId = GetGroupId(lstvwgrp); int groupIndex = Groups.IndexOf(lstvwgrp); var group = new NativeMethods.LVGROUP(); group.CbSize = Marshal.SizeOf(group); group.State = state; group.Mask = NativeMethods.ListViewGroupMask.State; var handleRef = new HandleRef(this, Handle); group.IGroupId = groupId > 0 ? groupId : groupIndex; NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SETGROUPINFO, (IntPtr)group.IGroupId, ref group); } }
internal void UpdateGroupNative(ListViewGroupEx group, bool invalidate = true) { using (NativeMethods.LVGROUP nGroup = new NativeMethods.LVGROUP(group)) { nGroup.SetState(NativeMethods.ListViewGroupState.Collapsible, collapsible); SendMessage(NativeMethods.ListViewMessage.SetGroupInfo, group.ID, nGroup); } if (invalidate) { base.Invalidate(); } }
public static void SetFooter(this ListViewGroup group, string footer = null, HorizontalAlignment footerAlignment = HorizontalAlignment.Left) { int groupId = GetGroupId(group); if (groupId >= 0) { using (NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.None)) { lvgroup.Footer = footer; lvgroup.SetAlignment(group.HeaderAlignment, footerAlignment); NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }
public static void SetTask(this ListViewGroup group, string task) { int groupId = GetGroupId(group); if (groupId >= 0) { using (NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.None)) { lvgroup.Task = task; NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }
internal int GetGroupId(ListViewGroup group) { NativeMethods.LVGROUP mgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.GroupId); try { if (0 != SendMessage(NativeMethods.ListViewMessage.GetGroupInfoByIndex, base.Groups.IndexOf(group), mgroup)) { return(mgroup.ID); } } catch { } return(-1); }
private static void SetState(ListViewGroup group, NativeMethods.ListViewGroupState state, bool value) { int groupId = GetGroupId(group); if (groupId >= 0) { NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.State); { lvgroup.SetState(state, value); NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }
public static void SetFooter(this ListViewGroup group, string footer = null, HorizontalAlignment footerAlignment = HorizontalAlignment.Left) { int groupId = GetGroupId(group); if (groupId >= 0) { using (NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.None)) { lvgroup.Footer = footer; lvgroup.SetAlignment(group.HeaderAlignment, footerAlignment); NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }
internal static bool IsCollapsed(IntPtr hwnd, int groupID) { bool isCollapsed = false; NativeMethods.LVGROUP group = new NativeMethods.LVGROUP(); group.Init(Marshal.SizeOf(typeof(NativeMethods.LVGROUP))); group.iGroupID = groupID; group.mask = NativeMethods.LVGF_STATE; group.stateMask = NativeMethods.LVGS_COLLAPSED; // Note: return code of GetGroupInfo() is not reliable. XSendMessage.GetGroupInfo(hwnd, ref group); // ignore return code. isCollapsed = (group.state & NativeMethods.LVGS_COLLAPSED) != 0; return(isCollapsed); }
public static void SetImage(this ListViewGroup group, int titleImageIndex, string descriptionTop = null, string descriptionBottom = null) { int groupId = GetGroupId(group); if (groupId >= 0) { using (NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.None)) { lvgroup.TitleImageIndex = titleImageIndex; if (descriptionBottom != null) lvgroup.DescriptionBottom = descriptionBottom; if (descriptionTop != null) lvgroup.DescriptionTop = descriptionTop; NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }
private void setGrpState(ListViewGroup lstvwgrp, ListViewGroupState state) { if (lstvwgrp == null) return; int? GrpId = GetGroupID(lstvwgrp); int gIndex = Groups.IndexOf(lstvwgrp); var group = new NativeMethods.LVGROUP(); group.CbSize = Marshal.SizeOf(group); group.State = state; group.Mask = NativeMethods.ListViewGroupMask.State; var handleRef = new HandleRef(this, Handle); group.IGroupId = GrpId ?? gIndex; NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SETGROUPINFO, (IntPtr)group.IGroupId, ref group); NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SETGROUPINFO, (IntPtr)group.IGroupId, ref group); Refresh(); }
public static void SetImage(this ListViewGroup group, int titleImageIndex, string descriptionTop = null, string descriptionBottom = null) { int groupId = GetGroupId(group); if (groupId >= 0) { using (NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.None)) { lvgroup.TitleImageIndex = titleImageIndex; if (descriptionBottom != null) { lvgroup.DescriptionBottom = descriptionBottom; } if (descriptionTop != null) { lvgroup.DescriptionTop = descriptionTop; } NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }
private void SetAllGroupState(NativeMethods.ListViewGroupState state, bool on = true) { NativeMethods.LVGROUP group = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.State); group.SetState(state, on); //group.Subtitle = "Dog"; foreach (ListViewGroup g in this.BaseGroups) { SendMessage(NativeMethods.ListViewMessage.SetGroupInfo, GetGroupId(g), group); } using (NativeMethods.LVGROUP grp = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.Subtitle)) { int res = SendMessage(NativeMethods.ListViewMessage.GetGroupInfoByIndex, 0, grp); if (res >= 0) { System.Diagnostics.Debug.WriteLine(grp.Subtitle); } } RecreateHandle(); }
internal void UpdateGroupNative(ListViewGroup group) { Debug.Assert(IsHandleCreated,"UpdateGroupNative precondition: list-view handle must be created"); Debug.Assert(ComctlSupportsVisualStyles, "we should have checked this already"); NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(); try { lvgroup = GetLVGROUP(group); int retval = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_SETGROUPINFO, group.ID, lvgroup); Debug.Assert(retval != -1, "Failed to set group info"); } finally { DestroyLVGROUP(lvgroup); } // The comctl32 ListView does not correctly invalidate itself, so we need to invalidate the entire ListView // Invalidate(); }
public static void SetTask(this ListViewGroup group, string task) { int groupId = GetGroupId(group); if (groupId >= 0) { using (NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.None)) { lvgroup.Task = task; NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }
private int SendMessage(NativeMethods.ListViewMessage msg, int wParam, NativeMethods.LVGROUP group) { return(NativeMethods.SendMessage(this.Handle, msg, wParam, group).ToInt32()); }
private int SendMessage(NativeMethods.ListViewMessage msg, int wParam, NativeMethods.LVGROUP group) => NativeMethods.SendMessage(Handle, msg, wParam, group).ToInt32();
protected override void WndProc(ref Message m) { var message = m; var groupHitInfo = new Lazy <ListViewGroupHitInfo>(() => GetGroupHitInfo(message)); switch (m.Msg) { case NativeMethods.WM_LBUTTONUP when groupHitInfo.Value?.IsCollapseButton == true: DefWndProc(ref m); // collapse / expand by clicking button in group header break; case NativeMethods.LVM_INSERTGROUP: base.WndProc(ref m); HandleAddedGroup(m); break; case NativeMethods.WM_PAINT: _isInWmPaintMsg = true; base.WndProc(ref m); _isInWmPaintMsg = false; break; case NativeMethods.WM_REFLECT_NOTIFY when IsCustomDraw(m) && !_isInWmPaintMsg: case NativeMethods.WM_RBUTTONUP when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Right, isDown: false) : case NativeMethods.WM_RBUTTONDOWN when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Right, isDown: true) : case NativeMethods.WM_LBUTTONUP when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Left, isDown: false) : case NativeMethods.WM_LBUTTONDOWN when IsGroupMouseEventHandled(groupHitInfo.Value, MouseButtons.Left, isDown: true) : break; default: base.WndProc(ref m); break; } void HandleAddedGroup(Message msg) { if (!IsGroupStateSupported || !AllowCollapseGroups) { return; } int groupIndex = GetGroupIndex(); if (groupIndex < _minGroupInsertionIndex) { return; } var listViewGroup = Groups[groupIndex]; SetGrpState(listViewGroup, ListViewGroupState.Collapsible); Invalidate(); int GetGroupIndex() { // https://docs.microsoft.com/en-us/windows/desktop/controls/lvm-insertgroup int index = msg.WParam.ToInt32(); if (index == -1) { // -1 because addition already happened return(Groups.Count - 1); } return(index - 1 + _minGroupInsertionIndex); } void SetGrpState(ListViewGroup grp, ListViewGroupState state) { int groupId = GetGroupId(grp); if (groupId < 0) { groupId = Groups.IndexOf(grp) - _minGroupInsertionIndex; } var lvgroup = new NativeMethods.LVGROUP(); lvgroup.CbSize = Marshal.SizeOf(lvgroup); lvgroup.State = state; lvgroup.Mask = NativeMethods.ListViewGroupMask.State; lvgroup.IGroupId = groupId; var handleRef = new HandleRef(this, Handle); NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SETGROUPINFO, (IntPtr)groupId, ref lvgroup); } } bool IsGroupMouseEventHandled(ListViewGroupHitInfo hitInfo, MouseButtons button, bool isDown) { if (hitInfo == null) { return(false); } var eventArgs = new ListViewGroupMouseEventArgs(button, hitInfo, 1, 0); if (isDown) { GroupMouseDown?.Invoke(this, eventArgs); } else { GroupMouseUp?.Invoke(this, eventArgs); } return(eventArgs.Handled); } bool IsCustomDraw(Message msg) { var nmhdr = (NativeMethods.NMHDR)msg.GetLParam(typeof(NativeMethods.NMHDR)); return(nmhdr.code == NativeMethods.NM_CUSTOMDRAW); } }
private NativeMethods.LVGROUP GetLVGROUP(ListViewGroup group) { NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(); lvgroup.mask = NativeMethods.LVGF_HEADER | NativeMethods.LVGF_GROUPID | NativeMethods.LVGF_ALIGN; // Header // String header = group.Header; lvgroup.pszHeader = Marshal.StringToHGlobalAuto(header); lvgroup.cchHeader = header.Length; // Group ID // lvgroup.iGroupId = group.ID; // Alignment // switch(group.HeaderAlignment) { case HorizontalAlignment.Left: lvgroup.uAlign = NativeMethods.LVGA_HEADER_LEFT; break; case HorizontalAlignment.Right: lvgroup.uAlign = NativeMethods.LVGA_HEADER_RIGHT; break; case HorizontalAlignment.Center: lvgroup.uAlign = NativeMethods.LVGA_HEADER_CENTER; break; } return lvgroup; }
// does the Win32 part of the job of inserting the group private void InsertGroupNative(int index, ListViewGroup group) { Debug.Assert(IsHandleCreated,"InsertGroupNative precondition: list-view handle must be created"); Debug.Assert(group == DefaultGroup || this.Groups.Contains(group),"Make sure ListView.Groups contains this group before adding the native LVGROUP. Otherwise, custom-drawing may break."); NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(); try { lvgroup = GetLVGROUP(group); int retval = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this,this.Handle),NativeMethods.LVM_INSERTGROUP,index,lvgroup); Debug.Assert(retval != -1,"Failed to insert group"); } finally { DestroyLVGROUP(lvgroup); } }
internal void SetGroupState(ListViewGroupEx group, NativeMethods.ListViewGroupState item, bool value) { NativeMethods.LVGROUP mgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.State); mgroup.SetState(item, value); SendMessage(NativeMethods.ListViewMessage.SetGroupInfo, GetGroupId(group), mgroup); }
protected override void WndProc(ref Message m) { var message = m; switch (m.Msg) { case NativeMethods.WM_LBUTTONUP when GetGroupHitInfo(message.LParam.ToPoint())?.IsCollapseButton == true: DefWndProc(ref m); // collapse / expand by clicking button in group header break; case NativeMethods.LVM_INSERTGROUP: base.WndProc(ref m); HandleAddedGroup(m); break; case NativeMethods.WM_RBUTTONUP when IsGroupMouseEventHandled(MouseButtons.Right, isDown: false) : case NativeMethods.WM_RBUTTONDOWN when IsGroupMouseEventHandled(MouseButtons.Right, isDown: true) : case NativeMethods.WM_LBUTTONUP when IsGroupMouseEventHandled(MouseButtons.Left, isDown: false) : case NativeMethods.WM_LBUTTONDOWN when IsGroupMouseEventHandled(MouseButtons.Left, isDown: true) : break; default: HandleScroll(m); base.WndProc(ref m); break; } void HandleScroll(Message msg) { ScrollEventType type; int? newValue = null; switch (msg.Msg) { case NativeMethods.WM_VSCROLL: type = (ScrollEventType)LowWord(msg.WParam.ToInt64()); newValue = HighWord(msg.WParam.ToInt64()); break; case NativeMethods.WM_MOUSEWHEEL: type = HighWord(msg.WParam.ToInt64()) > 0 ? ScrollEventType.SmallDecrement : ScrollEventType.SmallIncrement; break; case NativeMethods.WM_KEYDOWN: switch ((Keys)msg.WParam.ToInt32()) { case Keys.Up: type = ScrollEventType.SmallDecrement; break; case Keys.Down: type = ScrollEventType.SmallIncrement; break; case Keys.PageUp: type = ScrollEventType.LargeDecrement; break; case Keys.PageDown: type = ScrollEventType.LargeIncrement; break; case Keys.Home: type = ScrollEventType.First; break; case Keys.End: type = ScrollEventType.Last; break; default: return; } break; default: return; } newValue = newValue ?? NativeMethods.GetScrollPos(Handle, NativeMethods.SB_VERT); Scroll?.Invoke(this, new ScrollEventArgs(type, newValue.Value)); short LowWord(long number) => unchecked ((short)(number & 0x0000ffff)); short HighWord(long number) => unchecked ((short)(number >> 16)); } void HandleAddedGroup(Message msg) { if (!IsGroupStateSupported || !AllowCollapseGroups) { return; } int groupIndex = GetGroupIndex(); if (groupIndex < _minGroupInsertionIndex) { return; } var listViewGroup = Groups[groupIndex]; SetGrpState(listViewGroup, ListViewGroupState.Collapsible); Invalidate(); int GetGroupIndex() { // https://docs.microsoft.com/en-us/windows/desktop/controls/lvm-insertgroup int index = msg.WParam.ToInt32(); if (index == -1) { // -1 because addition already happened return(Groups.Count - 1); } return(index - 1 + _minGroupInsertionIndex); } void SetGrpState(ListViewGroup grp, ListViewGroupState state) { int groupId = GetGroupId(grp); if (groupId < 0) { groupId = Groups.IndexOf(grp) - _minGroupInsertionIndex; } var lvgroup = new NativeMethods.LVGROUP(); lvgroup.CbSize = Marshal.SizeOf(lvgroup); lvgroup.State = state; lvgroup.Mask = NativeMethods.ListViewGroupMask.State; lvgroup.IGroupId = groupId; var handleRef = new HandleRef(this, Handle); NativeMethods.SendMessage(handleRef, NativeMethods.LVM_SETGROUPINFO, (IntPtr)groupId, ref lvgroup); } } bool IsGroupMouseEventHandled(MouseButtons button, bool isDown) { var hitInfo = GetGroupHitInfo(message.LParam.ToPoint()); if (hitInfo == null) { return(false); } var eventArgs = new ListViewGroupMouseEventArgs(button, hitInfo, 1, 0); if (isDown) { GroupMouseDown?.Invoke(this, eventArgs); } else { GroupMouseUp?.Invoke(this, eventArgs); } return(eventArgs.Handled); } }
private static void SetState(ListViewGroup group, NativeMethods.ListViewGroupState state, bool value) { int groupId = GetGroupId(group); if (groupId >= 0) { NativeMethods.LVGROUP lvgroup = new NativeMethods.LVGROUP(NativeMethods.ListViewGroupMask.State); { lvgroup.SetState(state, value); NativeMethods.SendMessage(group.ListView.Handle, (uint)NativeMethods.ListViewMessage.SetGroupInfo, (IntPtr)groupId, lvgroup); } } }