------ #### ryControls V2.1.2101.1201 - *.[更新]内置的ObjectListView从1.13更新到2.9.1版本,并对主要属性进行汉化。 - *.[修复]修复新版ObjectListView选中项有筛选结果时,筛选结果白色字体看不清的BUG。 - *.[改进]TextBoxEx2默认事件改为TextChanged2。
748 lines
24 KiB
C#
748 lines
24 KiB
C#
/*
|
|
* Groups - Enhancements to the normal ListViewGroup
|
|
*
|
|
* Author: Phillip Piper
|
|
* Date: 22/08/2009 6:03PM
|
|
*
|
|
* Change log:
|
|
* v2.3
|
|
* 2009-09-09 JPP - Added Collapsed and Collapsible properties
|
|
* 2009-09-01 JPP - Cleaned up code, added more docs
|
|
* - Works under VS2005 again
|
|
* 2009-08-22 JPP - Initial version
|
|
*
|
|
* To do:
|
|
* - Implement subseting
|
|
* - Implement footer items
|
|
*
|
|
* Copyright (C) 2009-2014 Phillip Piper
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* If you wish to use this code in a closed source application, please contact phillip.piper@gmail.com.
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using System.Windows.Forms;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace BrightIdeasSoftware
|
|
{
|
|
/// <summary>
|
|
/// These values indicate what is the state of the group. These values
|
|
/// are taken directly from the SDK and many are not used by ObjectListView.
|
|
/// </summary>
|
|
[Flags]
|
|
public enum GroupState
|
|
{
|
|
/// <summary>
|
|
/// Normal
|
|
/// </summary>
|
|
LVGS_NORMAL = 0x0,
|
|
|
|
/// <summary>
|
|
/// Collapsed
|
|
/// </summary>
|
|
LVGS_COLLAPSED = 0x1,
|
|
|
|
/// <summary>
|
|
/// Hidden
|
|
/// </summary>
|
|
LVGS_HIDDEN = 0x2,
|
|
|
|
/// <summary>
|
|
/// NoHeader
|
|
/// </summary>
|
|
LVGS_NOHEADER = 0x4,
|
|
|
|
/// <summary>
|
|
/// Can be collapsed
|
|
/// </summary>
|
|
LVGS_COLLAPSIBLE = 0x8,
|
|
|
|
/// <summary>
|
|
/// Has focus
|
|
/// </summary>
|
|
LVGS_FOCUSED = 0x10,
|
|
|
|
/// <summary>
|
|
/// Is Selected
|
|
/// </summary>
|
|
LVGS_SELECTED = 0x20,
|
|
|
|
/// <summary>
|
|
/// Is subsetted
|
|
/// </summary>
|
|
LVGS_SUBSETED = 0x40,
|
|
|
|
/// <summary>
|
|
/// Subset link has focus
|
|
/// </summary>
|
|
LVGS_SUBSETLINKFOCUSED = 0x80,
|
|
|
|
/// <summary>
|
|
/// All styles
|
|
/// </summary>
|
|
LVGS_ALL = 0xFFFF
|
|
}
|
|
|
|
/// <summary>
|
|
/// This mask indicates which members of a LVGROUP have valid data. These values
|
|
/// are taken directly from the SDK and many are not used by ObjectListView.
|
|
/// </summary>
|
|
[Flags]
|
|
public enum GroupMask
|
|
{
|
|
/// <summary>
|
|
/// No mask
|
|
/// </summary>
|
|
LVGF_NONE = 0,
|
|
|
|
/// <summary>
|
|
/// Group has header
|
|
/// </summary>
|
|
LVGF_HEADER = 1,
|
|
|
|
/// <summary>
|
|
/// Group has footer
|
|
/// </summary>
|
|
LVGF_FOOTER = 2,
|
|
|
|
/// <summary>
|
|
/// Group has state
|
|
/// </summary>
|
|
LVGF_STATE = 4,
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
LVGF_ALIGN = 8,
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
LVGF_GROUPID = 0x10,
|
|
|
|
/// <summary>
|
|
/// pszSubtitle is valid
|
|
/// </summary>
|
|
LVGF_SUBTITLE = 0x00100,
|
|
|
|
/// <summary>
|
|
/// pszTask is valid
|
|
/// </summary>
|
|
LVGF_TASK = 0x00200,
|
|
|
|
/// <summary>
|
|
/// pszDescriptionTop is valid
|
|
/// </summary>
|
|
LVGF_DESCRIPTIONTOP = 0x00400,
|
|
|
|
/// <summary>
|
|
/// pszDescriptionBottom is valid
|
|
/// </summary>
|
|
LVGF_DESCRIPTIONBOTTOM = 0x00800,
|
|
|
|
/// <summary>
|
|
/// iTitleImage is valid
|
|
/// </summary>
|
|
LVGF_TITLEIMAGE = 0x01000,
|
|
|
|
/// <summary>
|
|
/// iExtendedImage is valid
|
|
/// </summary>
|
|
LVGF_EXTENDEDIMAGE = 0x02000,
|
|
|
|
/// <summary>
|
|
/// iFirstItem and cItems are valid
|
|
/// </summary>
|
|
LVGF_ITEMS = 0x04000,
|
|
|
|
/// <summary>
|
|
/// pszSubsetTitle is valid
|
|
/// </summary>
|
|
LVGF_SUBSET = 0x08000,
|
|
|
|
/// <summary>
|
|
/// readonly, cItems holds count of items in visible subset, iFirstItem is valid
|
|
/// </summary>
|
|
LVGF_SUBSETITEMS = 0x10000
|
|
}
|
|
|
|
/// <summary>
|
|
/// This mask indicates which members of a GROUPMETRICS structure are valid
|
|
/// </summary>
|
|
[Flags]
|
|
public enum GroupMetricsMask
|
|
{
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
LVGMF_NONE = 0,
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
LVGMF_BORDERSIZE = 1,
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
LVGMF_BORDERCOLOR = 2,
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
LVGMF_TEXTCOLOR = 4
|
|
}
|
|
|
|
/// <summary>
|
|
/// Instances of this class enhance the capabilities of a normal ListViewGroup,
|
|
/// enabling the functionality that was released in v6 of the common controls.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// In this implementation (2009-09), these objects are essentially passive.
|
|
/// Setting properties does not automatically change the associated group in
|
|
/// the listview. Collapsed and Collapsible are two exceptions to this and
|
|
/// give immediate results.
|
|
/// </para>
|
|
/// <para>
|
|
/// This really should be a subclass of ListViewGroup, but that class is
|
|
/// sealed (why is that?). So this class provides the same interface as a
|
|
/// ListViewGroup, plus many other new properties.
|
|
/// </para>
|
|
/// </remarks>
|
|
public class OLVGroup
|
|
{
|
|
#region Creation
|
|
|
|
/// <summary>
|
|
/// Create an OLVGroup
|
|
/// </summary>
|
|
public OLVGroup() : this("默认组标题") {
|
|
}
|
|
|
|
/// <summary>
|
|
/// 按指定标题创建分组
|
|
/// </summary>
|
|
/// <param name="header">分组标题</param>
|
|
public OLVGroup(string header) {
|
|
this.Header = header;
|
|
this.Id = OLVGroup.nextId++;
|
|
this.TitleImage = -1;
|
|
this.ExtendedImage = -1;
|
|
}
|
|
private static int nextId;
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
/// <summary>
|
|
/// Gets or sets the bottom description of the group
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Descriptions only appear when group is centered and there is a title image
|
|
/// </remarks>
|
|
public string BottomDescription {
|
|
get { return this.bottomDescription; }
|
|
set { this.bottomDescription = value; }
|
|
}
|
|
private string bottomDescription;
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether or not this group is collapsed
|
|
/// </summary>
|
|
public bool Collapsed {
|
|
get { return this.GetOneState(GroupState.LVGS_COLLAPSED); }
|
|
set { this.SetOneState(value, GroupState.LVGS_COLLAPSED); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether or not this group can be collapsed
|
|
/// </summary>
|
|
public bool Collapsible {
|
|
get { return this.GetOneState(GroupState.LVGS_COLLAPSIBLE); }
|
|
set { this.SetOneState(value, GroupState.LVGS_COLLAPSIBLE); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets some representation of the contents of this group
|
|
/// </summary>
|
|
/// <remarks>This is user defined (like Tag)</remarks>
|
|
public IList Contents {
|
|
get { return this.contents; }
|
|
set { this.contents = value; }
|
|
}
|
|
private IList contents;
|
|
|
|
/// <summary>
|
|
/// Gets whether this group has been created.
|
|
/// </summary>
|
|
public bool Created {
|
|
get { return this.ListView != null; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the int or string that will select the extended image to be shown against the title
|
|
/// </summary>
|
|
public object ExtendedImage {
|
|
get { return this.extendedImage; }
|
|
set { this.extendedImage = value; }
|
|
}
|
|
private object extendedImage;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the footer of the group
|
|
/// </summary>
|
|
public string Footer {
|
|
get { return this.footer; }
|
|
set { this.footer = value; }
|
|
}
|
|
private string footer;
|
|
|
|
/// <summary>
|
|
/// Gets the internal id of our associated ListViewGroup.
|
|
/// </summary>
|
|
public int GroupId {
|
|
get {
|
|
if (this.ListViewGroup == null)
|
|
return this.Id;
|
|
|
|
// Use reflection to get around the access control on the ID property
|
|
if (OLVGroup.groupIdPropInfo == null) {
|
|
OLVGroup.groupIdPropInfo = typeof(ListViewGroup).GetProperty("ID",
|
|
BindingFlags.NonPublic | BindingFlags.Instance);
|
|
System.Diagnostics.Debug.Assert(OLVGroup.groupIdPropInfo != null);
|
|
}
|
|
|
|
int? groupId = OLVGroup.groupIdPropInfo.GetValue(this.ListViewGroup, null) as int?;
|
|
return groupId.HasValue ? groupId.Value : -1;
|
|
}
|
|
}
|
|
private static PropertyInfo groupIdPropInfo;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the header of the group
|
|
/// </summary>
|
|
public string Header {
|
|
get { return this.header; }
|
|
set { this.header = value; }
|
|
}
|
|
private string header;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the horizontal alignment of the group header
|
|
/// </summary>
|
|
public HorizontalAlignment HeaderAlignment {
|
|
get { return this.headerAlignment; }
|
|
set { this.headerAlignment = value; }
|
|
}
|
|
private HorizontalAlignment headerAlignment;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the internally created id of the group
|
|
/// </summary>
|
|
public int Id {
|
|
get { return this.id; }
|
|
set { this.id = value; }
|
|
}
|
|
private int id;
|
|
|
|
/// <summary>
|
|
/// Gets or sets ListViewItems that are members of this group
|
|
/// </summary>
|
|
/// <remarks>Listener of the BeforeCreatingGroups event can populate this collection.
|
|
/// It is only used on non-virtual lists.</remarks>
|
|
public IList<OLVListItem> Items {
|
|
get { return this.items; }
|
|
set { this.items = value; }
|
|
}
|
|
private IList<OLVListItem> items = new List<OLVListItem>();
|
|
|
|
/// <summary>
|
|
/// Gets or sets the key that was used to partition objects into this group
|
|
/// </summary>
|
|
/// <remarks>This is user defined (like Tag)</remarks>
|
|
public object Key {
|
|
get { return this.key; }
|
|
set { this.key = value; }
|
|
}
|
|
private object key;
|
|
|
|
/// <summary>
|
|
/// Gets the ObjectListView that this group belongs to
|
|
/// </summary>
|
|
/// <remarks>If this is null, the group has not yet been created.</remarks>
|
|
public ObjectListView ListView {
|
|
get { return this.listView; }
|
|
protected set { this.listView = value; }
|
|
}
|
|
private ObjectListView listView;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the name of the group
|
|
/// </summary>
|
|
/// <remarks>As of 2009-09-01, this property is not used.</remarks>
|
|
public string Name {
|
|
get { return this.name; }
|
|
set { this.name = value; }
|
|
}
|
|
private string name;
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether this group is focused
|
|
/// </summary>
|
|
public bool Focused
|
|
{
|
|
get { return this.GetOneState(GroupState.LVGS_FOCUSED); }
|
|
set { this.SetOneState(value, GroupState.LVGS_FOCUSED); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether this group is selected
|
|
/// </summary>
|
|
public bool Selected
|
|
{
|
|
get { return this.GetOneState(GroupState.LVGS_SELECTED); }
|
|
set { this.SetOneState(value, GroupState.LVGS_SELECTED); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the text that will show that this group is subsetted
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// As of WinSDK v7.0, subsetting of group is officially unimplemented.
|
|
/// We can get around this using undocumented interfaces and may do so.
|
|
/// </remarks>
|
|
public string SubsetTitle {
|
|
get { return this.subsetTitle; }
|
|
set { this.subsetTitle = value; }
|
|
}
|
|
private string subsetTitle;
|
|
|
|
/// <summary>
|
|
/// Gets or set the subtitleof the task
|
|
/// </summary>
|
|
public string Subtitle {
|
|
get { return this.subtitle; }
|
|
set { this.subtitle = value; }
|
|
}
|
|
private string subtitle;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the value by which this group will be sorted.
|
|
/// </summary>
|
|
public IComparable SortValue {
|
|
get { return this.sortValue; }
|
|
set { this.sortValue = value; }
|
|
}
|
|
private IComparable sortValue;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the state of the group
|
|
/// </summary>
|
|
public GroupState State {
|
|
get { return this.state; }
|
|
set { this.state = value; }
|
|
}
|
|
private GroupState state;
|
|
|
|
/// <summary>
|
|
/// Gets or sets which bits of State are valid
|
|
/// </summary>
|
|
public GroupState StateMask {
|
|
get { return this.stateMask; }
|
|
set { this.stateMask = value; }
|
|
}
|
|
private GroupState stateMask;
|
|
|
|
/// <summary>
|
|
/// Gets or sets whether this group is showing only a subset of its elements
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// As of WinSDK v7.0, this property officially does nothing.
|
|
/// </remarks>
|
|
public bool Subseted {
|
|
get { return this.GetOneState(GroupState.LVGS_SUBSETED); }
|
|
set { this.SetOneState(value, GroupState.LVGS_SUBSETED); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the user-defined data attached to this group
|
|
/// </summary>
|
|
public object Tag {
|
|
get { return this.tag; }
|
|
set { this.tag = value; }
|
|
}
|
|
private object tag;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the task of this group
|
|
/// </summary>
|
|
/// <remarks>This task is the clickable text that appears on the right margin
|
|
/// of the group header.</remarks>
|
|
public string Task {
|
|
get { return this.task; }
|
|
set { this.task = value; }
|
|
}
|
|
private string task;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the int or string that will select the image to be shown against the title
|
|
/// </summary>
|
|
public object TitleImage {
|
|
get { return this.titleImage; }
|
|
set { this.titleImage = value; }
|
|
}
|
|
private object titleImage;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the top description of the group
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Descriptions only appear when group is centered and there is a title image
|
|
/// </remarks>
|
|
public string TopDescription {
|
|
get { return this.topDescription; }
|
|
set { this.topDescription = value; }
|
|
}
|
|
private string topDescription;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the number of items that are within this group.
|
|
/// </summary>
|
|
/// <remarks>This should only be used for virtual groups.</remarks>
|
|
public int VirtualItemCount {
|
|
get { return this.virtualItemCount; }
|
|
set { this.virtualItemCount = value; }
|
|
}
|
|
private int virtualItemCount;
|
|
|
|
#endregion
|
|
|
|
#region Protected properties
|
|
|
|
/// <summary>
|
|
/// Gets or sets the ListViewGroup that is shadowed by this group.
|
|
/// </summary>
|
|
/// <remarks>For virtual groups, this will always be null.</remarks>
|
|
protected ListViewGroup ListViewGroup {
|
|
get { return this.listViewGroup; }
|
|
set { this.listViewGroup = value; }
|
|
}
|
|
private ListViewGroup listViewGroup;
|
|
#endregion
|
|
|
|
#region Calculations/Conversions
|
|
|
|
/// <summary>
|
|
/// Calculate the index into the group image list of the given image selector
|
|
/// </summary>
|
|
/// <param name="imageSelector"></param>
|
|
/// <returns></returns>
|
|
public int GetImageIndex(object imageSelector) {
|
|
if (imageSelector == null || this.ListView == null || this.ListView.GroupImageList == null)
|
|
return -1;
|
|
|
|
if (imageSelector is Int32)
|
|
return (int)imageSelector;
|
|
|
|
String imageSelectorAsString = imageSelector as String;
|
|
if (imageSelectorAsString != null)
|
|
return this.ListView.GroupImageList.Images.IndexOfKey(imageSelectorAsString);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert this object to a string representation
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override string ToString() {
|
|
return this.Header;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Commands
|
|
|
|
/// <summary>
|
|
/// Insert a native group into the underlying Windows control,
|
|
/// *without* using a ListViewGroup
|
|
/// </summary>
|
|
/// <param name="olv"></param>
|
|
/// <remarks>This is used when creating virtual groups</remarks>
|
|
public void InsertGroupNewStyle(ObjectListView olv) {
|
|
this.ListView = olv;
|
|
NativeMethods.InsertGroup(olv, this.AsNativeGroup(true));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Insert a native group into the underlying control via a ListViewGroup
|
|
/// </summary>
|
|
/// <param name="olv"></param>
|
|
public void InsertGroupOldStyle(ObjectListView olv) {
|
|
this.ListView = olv;
|
|
|
|
// Create/update the associated ListViewGroup
|
|
if (this.ListViewGroup == null)
|
|
this.ListViewGroup = new ListViewGroup();
|
|
this.ListViewGroup.Header = this.Header;
|
|
this.ListViewGroup.HeaderAlignment = this.HeaderAlignment;
|
|
this.ListViewGroup.Name = this.Name;
|
|
|
|
// Remember which OLVGroup created the ListViewGroup
|
|
this.ListViewGroup.Tag = this;
|
|
|
|
// Add the group to the control
|
|
olv.Groups.Add(this.ListViewGroup);
|
|
|
|
// Add any extra information
|
|
NativeMethods.SetGroupInfo(olv, this.GroupId, this.AsNativeGroup(false));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Change the members of the group to match the current contents of Items,
|
|
/// using a ListViewGroup
|
|
/// </summary>
|
|
public void SetItemsOldStyle() {
|
|
List<OLVListItem> list = this.Items as List<OLVListItem>;
|
|
if (list == null) {
|
|
foreach (OLVListItem item in this.Items) {
|
|
this.ListViewGroup.Items.Add(item);
|
|
}
|
|
} else {
|
|
this.ListViewGroup.Items.AddRange(list.ToArray());
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Implementation
|
|
|
|
/// <summary>
|
|
/// Create a native LVGROUP structure that matches this group
|
|
/// </summary>
|
|
internal NativeMethods.LVGROUP2 AsNativeGroup(bool withId) {
|
|
|
|
NativeMethods.LVGROUP2 group = new NativeMethods.LVGROUP2();
|
|
group.cbSize = (uint)Marshal.SizeOf(typeof(NativeMethods.LVGROUP2));
|
|
group.mask = (uint)(GroupMask.LVGF_HEADER ^ GroupMask.LVGF_ALIGN ^ GroupMask.LVGF_STATE);
|
|
group.pszHeader = this.Header;
|
|
group.uAlign = (uint)this.HeaderAlignment;
|
|
group.stateMask = (uint)this.StateMask;
|
|
group.state = (uint)this.State;
|
|
|
|
if (withId) {
|
|
group.iGroupId = this.GroupId;
|
|
group.mask ^= (uint)GroupMask.LVGF_GROUPID;
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(this.Footer)) {
|
|
group.pszFooter = this.Footer;
|
|
group.mask ^= (uint)GroupMask.LVGF_FOOTER;
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(this.Subtitle)) {
|
|
group.pszSubtitle = this.Subtitle;
|
|
group.mask ^= (uint)GroupMask.LVGF_SUBTITLE;
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(this.Task)) {
|
|
group.pszTask = this.Task;
|
|
group.mask ^= (uint)GroupMask.LVGF_TASK;
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(this.TopDescription)) {
|
|
group.pszDescriptionTop = this.TopDescription;
|
|
group.mask ^= (uint)GroupMask.LVGF_DESCRIPTIONTOP;
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(this.BottomDescription)) {
|
|
group.pszDescriptionBottom = this.BottomDescription;
|
|
group.mask ^= (uint)GroupMask.LVGF_DESCRIPTIONBOTTOM;
|
|
}
|
|
|
|
int imageIndex = this.GetImageIndex(this.TitleImage);
|
|
if (imageIndex >= 0) {
|
|
group.iTitleImage = imageIndex;
|
|
group.mask ^= (uint)GroupMask.LVGF_TITLEIMAGE;
|
|
}
|
|
|
|
imageIndex = this.GetImageIndex(this.ExtendedImage);
|
|
if (imageIndex >= 0) {
|
|
group.iExtendedImage = imageIndex;
|
|
group.mask ^= (uint)GroupMask.LVGF_EXTENDEDIMAGE;
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(this.SubsetTitle)) {
|
|
group.pszSubsetTitle = this.SubsetTitle;
|
|
group.mask ^= (uint)GroupMask.LVGF_SUBSET;
|
|
}
|
|
|
|
if (this.VirtualItemCount > 0) {
|
|
group.cItems = this.VirtualItemCount;
|
|
group.mask ^= (uint)GroupMask.LVGF_ITEMS;
|
|
}
|
|
|
|
return group;
|
|
}
|
|
|
|
private bool GetOneState(GroupState mask) {
|
|
if (this.Created)
|
|
this.State = this.GetState();
|
|
return (this.State & mask) == mask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the current state of this group from the underlying control
|
|
/// </summary>
|
|
protected GroupState GetState() {
|
|
return NativeMethods.GetGroupState(this.ListView, this.GroupId, GroupState.LVGS_ALL);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the current state of this group from the underlying control
|
|
/// </summary>
|
|
protected int SetState(GroupState newState, GroupState mask) {
|
|
NativeMethods.LVGROUP2 group = new NativeMethods.LVGROUP2();
|
|
group.cbSize = ((uint)Marshal.SizeOf(typeof(NativeMethods.LVGROUP2)));
|
|
group.mask = (uint)GroupMask.LVGF_STATE;
|
|
group.state = (uint)newState;
|
|
group.stateMask = (uint)mask;
|
|
return NativeMethods.SetGroupInfo(this.ListView, this.GroupId, group);
|
|
}
|
|
|
|
private void SetOneState(bool value, GroupState mask)
|
|
{
|
|
this.StateMask ^= mask;
|
|
if (value)
|
|
this.State ^= mask;
|
|
else
|
|
this.State &= ~mask;
|
|
|
|
if (this.Created)
|
|
this.SetState(this.State, mask);
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|