2023-09-24 17:26:46 -04:00
using System.Collections ;
2020-02-12 22:36:39 -05:00
using System.Collections.Generic ;
using System.ComponentModel ;
2020-08-06 19:16:40 -04:00
using System.Diagnostics ;
2020-02-12 22:36:39 -05:00
using System.Drawing ;
using System.Linq ;
using System.Windows.Forms ;
using Vanara.PInvoke ;
using Vanara.Windows.Shell ;
2020-12-14 18:12:11 -05:00
using static Vanara . PInvoke . Ole32 ;
2020-02-12 22:36:39 -05:00
using static Vanara . PInvoke . Shell32 ;
2020-08-06 19:16:40 -04:00
using static Vanara . PInvoke . User32 ;
2022-01-14 09:32:51 -05:00
using DragEventArgs = System . Windows . Forms . DragEventArgs ;
2020-12-14 18:12:11 -05:00
using IMessageFilter = System . Windows . Forms . IMessageFilter ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
namespace Vanara.Windows.Forms ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The location on the IShellItem that was clicked.</summary>
public enum ItemHitLocation
{
/// <summary>The click missed the IShellItem.</summary>
NoWhere = NSTCEHITTEST . NSTCEHT_NOWHERE ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the icon of the IShellItem.</summary>
OnIcon = NSTCEHITTEST . NSTCEHT_ONITEMICON ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the label text of the IShellItem.</summary>
OnLabel = NSTCEHITTEST . NSTCEHT_ONITEMLABEL ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the indented space on the leftmost side of the IShellItem.</summary>
OnIndent = NSTCEHITTEST . NSTCEHT_ONITEMINDENT ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the expando button of the IShellItem.</summary>
OnButton = NSTCEHITTEST . NSTCEHT_ONITEMBUTTON ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the rightmost side of the text of the IShellItem.</summary>
OnRight = NSTCEHITTEST . NSTCEHT_ONITEMRIGHT ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the state icon of the IShellItem.</summary>
OnStateIcon = NSTCEHITTEST . NSTCEHT_ONITEMSTATEICON ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the item icon or the item label or the state icon of the IShellItem.</summary>
OnItem = NSTCEHITTEST . NSTCEHT_ONITEM ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The click was on the tab button of the IShellItem.</summary>
OnTabButton = NSTCEHITTEST . NSTCEHT_ONITEMTABBUTTON ,
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Actions on a <see cref="ShellNamespaceTreeControl"/> exposed through <see cref="ShellNamespaceTreeControlEventArgs"/>.</summary>
public enum ShellNamespaceTreeControlAction
{
/// <summary>Unknown action.</summary>
Unknown ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>A keystroke caused the action.</summary>
ByKeyboard ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>A mouse click caused the action.</summary>
ByMouse ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An item has been added.</summary>
AfterAdd ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An item has been deleted.</summary>
AfterDelete ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An item is about to be deleted.</summary>
BeforeDelete ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An item is being collapsed.</summary>
Collapse ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>An item is being expanded.</summary>
Expand
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Determines the image displayed to the right of an item in <see cref="ShellNamespaceTreeControl"/>.</summary>
public enum ShellTreeItemButton
{
/// <summary>No button is displayed to the right of an item.</summary>
None ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Displays an arrow on the right side of an item if the item is a folder. The action associated with the arrow is implementation specific.
/// </summary>
Arrow ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Displays a red X on the right side of an item. The action associated with the X is implementation specific.</summary>
Delete ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Displays a refresh button on the right side of an item. The action associated with the button is implementation specific.
/// </summary>
Refresh
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The style of check box to display.</summary>
public enum ShellTreeItemCheckBoxStyle
{
/// <summary>Display no check box. This is the default.</summary>
None ,
/// <summary>Adds a standard, two-state, checkbox icon on the leftmost side of a given item.</summary>
Normal ,
/// <summary>
/// Adds a checkbox icon on the leftmost side of a given item with a square in the center, that indicates that the node is partially selected.
/// </summary>
Partial ,
/// <summary>
/// Adds a checkbox icon on the leftmost side of a given item that contains a red X, which indicates that the item is excluded from
/// the current selection. Without this exclusion icon, selection of a parent item includes selection of its child items.
/// </summary>
Exclusion ,
/// <summary>
/// Adds a checkbox on the leftmost side of a given item that contains an icon of a dimmed check mark, that indicates that a node is
/// selected because its parent is selected.
/// </summary>
Dimmed
}
/// <summary>Specifies the state of a tree item.</summary>
[Flags]
public enum ShellTreeItemState : uint
{
/// <summary>The item has default state; it is not selected, expanded, bolded or disabled.</summary>
None = NSTCITEMSTATE . NSTCIS_NONE ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The item is selected.</summary>
Selected = NSTCITEMSTATE . NSTCIS_SELECTED ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The item is expanded.</summary>
Expanded = NSTCITEMSTATE . NSTCIS_EXPANDED ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The item is bold.</summary>
Bold = NSTCITEMSTATE . NSTCIS_BOLD ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The item is disabled.</summary>
Disabled = NSTCITEMSTATE . NSTCIS_DISABLED ,
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Windows 7 and later. The item is selected, but not expanded.</summary>
SelectedNotExpanded = NSTCITEMSTATE . NSTCIS_SELECTEDNOEXPAND ,
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>A control used to view and manipulate nodes in a tree of Shell items.</summary>
[Designer(typeof(Design.ShellNamespaceTreeControlDesigner)), DefaultProperty(nameof(ShowPlusMinus)), DefaultEvent(nameof(AfterSelect))]
[ToolboxItem(true), ToolboxBitmap(typeof(ShellNamespaceTreeControl), "ShellNamespaceTreeControl.bmp")]
[Description("A Shell object that displays a tree of shell items.")]
[ComVisible(true), Guid("0639efb8-7701-472e-863d-d6fbc543d736")]
public class ShellNamespaceTreeControl : Control , Shell32 . IServiceProvider , INameSpaceTreeControlEvents , INameSpaceTreeControlDropHandler , IMessageFilter //, INameSpaceTreeAccessible
{
2023-09-29 13:58:35 -04:00
internal INameSpaceTreeControl ? pCtrl ;
2023-03-31 11:47:53 -04:00
private const NSTCSTYLE defaultStyle = NSTCSTYLE . NSTCS_HASEXPANDOS | NSTCSTYLE . NSTCS_ROOTHASEXPANDO | NSTCSTYLE . NSTCS_FADEINOUTEXPANDOS |
NSTCSTYLE . NSTCS_NOINFOTIP | NSTCSTYLE . NSTCS_ALLOWJUNCTIONS | NSTCSTYLE . NSTCS_SHOWSELECTIONALWAYS | NSTCSTYLE . NSTCS_FULLROWSELECT |
NSTCSTYLE . NSTCS_TABSTOP ;
private const NSTCSTYLE2 defaultStyle2 = NSTCSTYLE2 . NTSCS2_NOSINGLETONAUTOEXPAND | NSTCSTYLE2 . NSTCS2_INTERRUPTNOTIFICATIONS |
NSTCSTYLE2 . NSTCS2_DISPLAYPINNEDONLY | NSTCSTYLE2 . NTSCS2_NEVERINSERTNONENUMERATED ;
private const NSTCITEMSTATE NSTCITEMSTATE_ALL = NSTCITEMSTATE . NSTCIS_SELECTED | NSTCITEMSTATE . NSTCIS_EXPANDED | NSTCITEMSTATE . NSTCIS_BOLD | NSTCITEMSTATE . NSTCIS_DISABLED | NSTCITEMSTATE . NSTCIS_SELECTEDNOEXPAND ;
private const NSTCSTYLE NSTCSTYLE_ALL = NSTCSTYLE . NSTCS_HASEXPANDOS | NSTCSTYLE . NSTCS_HASLINES | NSTCSTYLE . NSTCS_SINGLECLICKEXPAND |
NSTCSTYLE . NSTCS_FULLROWSELECT | NSTCSTYLE . NSTCS_SPRINGEXPAND | NSTCSTYLE . NSTCS_HORIZONTALSCROLL | NSTCSTYLE . NSTCS_ROOTHASEXPANDO |
NSTCSTYLE . NSTCS_SHOWSELECTIONALWAYS | NSTCSTYLE . NSTCS_NOINFOTIP | NSTCSTYLE . NSTCS_EVENHEIGHT | NSTCSTYLE . NSTCS_NOREPLACEOPEN |
NSTCSTYLE . NSTCS_DISABLEDRAGDROP | NSTCSTYLE . NSTCS_NOORDERSTREAM | NSTCSTYLE . NSTCS_RICHTOOLTIP | NSTCSTYLE . NSTCS_BORDER |
NSTCSTYLE . NSTCS_NOEDITLABELS | NSTCSTYLE . NSTCS_TABSTOP | NSTCSTYLE . NSTCS_FAVORITESMODE | NSTCSTYLE . NSTCS_AUTOHSCROLL |
NSTCSTYLE . NSTCS_FADEINOUTEXPANDOS | NSTCSTYLE . NSTCS_EMPTYTEXT | NSTCSTYLE . NSTCS_CHECKBOXES | NSTCSTYLE . NSTCS_PARTIALCHECKBOXES |
NSTCSTYLE . NSTCS_EXCLUSIONCHECKBOXES | NSTCSTYLE . NSTCS_DIMMEDCHECKBOXES | NSTCSTYLE . NSTCS_NOINDENTCHECKS |
NSTCSTYLE . NSTCS_ALLOWJUNCTIONS | NSTCSTYLE . NSTCS_SHOWTABSBUTTON | NSTCSTYLE . NSTCS_SHOWDELETEBUTTON | NSTCSTYLE . NSTCS_SHOWREFRESHBUTTON ;
private const NSTCSTYLE2 NSTCSTYLE2_ALL = NSTCSTYLE2 . NSTCS2_INTERRUPTNOTIFICATIONS | NSTCSTYLE2 . NSTCS2_SHOWNULLSPACEMENU |
NSTCSTYLE2 . NSTCS2_DISPLAYPADDING | NSTCSTYLE2 . NSTCS2_DISPLAYPINNEDONLY | NSTCSTYLE2 . NTSCS2_NOSINGLETONAUTOEXPAND |
NSTCSTYLE2 . NTSCS2_NEVERINSERTNONENUMERATED ;
private uint adviseCookie = uint . MaxValue ;
private BorderStyle borderStyle = BorderStyle . None ;
private HWND hWndNsTreeCtrl , hWndTreeView ;
private bool oleUninit = false ;
2023-09-29 13:58:35 -04:00
private INameSpaceTreeControl2 ? pCtrl2 ;
2023-03-31 11:47:53 -04:00
private EnumFlagIndexer < NSTCSTYLE > style = defaultStyle ;
private EnumFlagIndexer < NSTCSTYLE2 > style2 = defaultStyle2 ;
2023-09-29 13:58:35 -04:00
private string? theme = null ;
2023-03-31 11:47:53 -04:00
/// <summary>Initializes a new instance of the <see cref="ShellNamespaceTreeControl"/> class.</summary>
public ShellNamespaceTreeControl ( )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
RootItems = new ShellNamespaceTreeRootList ( this ) ;
BackColor = SystemColors . Window ;
2023-08-04 12:24:49 -04:00
oleUninit = OleInitialize ( ) . Succeeded ;
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called after an item is expanded.</summary>
[Category("Behavior"), Description("Occurs when an item has been expanded.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlEventArgs > ? AfterExpand ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called after an item has been added.</summary>
[Category("Behavior"), Description("Occurs when an item has been added.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlEventArgs > ? AfterItemAdd ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called after an item and all of its children are deleted.</summary>
[Category("Behavior"), Description("Occurs when an item has been deleted.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlEventArgs > ? AfterItemDelete ;
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Called after the item leaves edit mode.</summary>
[Category("Behavior"), Description("Occurs when the text of an item has been edited by the user.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlItemLabelEditEventArgs > ? AfterLabelEdit ;
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Occurs when the selection changes.</summary>
[Category("Behavior"), Description("Occurs when an item has been selected.")]
2023-09-29 13:58:35 -04:00
public event EventHandler ? AfterSelect ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called before an item is expanded.</summary>
[Category("Behavior"), Description("Occurs when an item it about to be expanded.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlCancelEventArgs > ? BeforeExpand ;
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Called before an item and all of its children are deleted.</summary>
[Category("Behavior"), Description("Occurs when an item is about to be deleted.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlCancelEventArgs > ? BeforeItemDelete ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called before the item goes into edit mode.</summary>
[Category("Behavior"), Description("Occurs when the text of an item is about to be edited by the user.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlItemLabelEditEventArgs > ? BeforeLabelEdit ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called when the user clicks a button on the mouse.</summary>
[Category("Behavior"), Description("Occurs when an item is clicked by the user.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlItemMouseClickEventArgs > ? ItemMouseClick ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Called when the user double-clicks a button on the mouse.</summary>
[Category("Behavior"), Description("Occurs when an item is double-clicked with the mouse.")]
2023-09-29 13:58:35 -04:00
public event EventHandler < ShellNamespaceTreeControlItemMouseClickEventArgs > ? ItemMouseDoubleClick ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether to insert spacing (padding) between top-level nodes.</summary>
[DefaultValue(false), Category("Appearance"), Description("Indicates whether to insert spacing (padding) between top-level nodes.")]
public bool AddTopLevelNodePadding
{
get = > HasTreeStyle ( NSTCSTYLE2 . NSTCS2_DISPLAYPADDING ) ;
set = > SetTreeStyle ( NSTCSTYLE2 . NSTCS2_DISPLAYPADDING , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Indicates whether to allow junctions. A junction point, or just junction, is a root of a namespace extension that is normally
/// displayed by Windows Explorer as a folder in both tree and folder views. For Windows Explorer to display your extension's files
/// and subfolders, you must specify where the root folder is located in the Shell namespace hierarchy. Junctions exist in the file
/// system as files, but are not treated as files. An example is a compressed file with a .zip file name extension, which to the
/// file system is just a file. However, if this file is treated as a junction, it can represent an entire namespace. This allows
/// the namespace tree control to treat compressed files and similar junctions as folders rather than as files.
/// </summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether to allow junctions.")]
public bool AllowJunctions
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_ALLOWJUNCTIONS ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_ALLOWJUNCTIONS , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the border style.</summary>
/// <value>The border style.</value>
[DefaultValue(BorderStyle.None), Category("Appearance"), Description("The border style of the control.")]
public BorderStyle BorderStyle
{
get = > borderStyle ;
set { if ( borderStyle ! = value ) { borderStyle = value ; /*InitializeControl();*/ } }
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Indicates whether to display check boxes on the leftmost side of the items. These check boxes can be of types partial, exclusion
/// or dimmed.
/// </summary>
[DefaultValue(ShellTreeItemCheckBoxStyle.None), Category("Appearance"), Description("Indicates the type of check boxes to display besides nodes.")]
public ShellTreeItemCheckBoxStyle CheckBoxStyle
{
get = > style switch
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
var s when s [ NSTCSTYLE . NSTCS_PARTIALCHECKBOXES ] = > ShellTreeItemCheckBoxStyle . Partial ,
var s when s [ NSTCSTYLE . NSTCS_EXCLUSIONCHECKBOXES ] = > ShellTreeItemCheckBoxStyle . Exclusion ,
var s when s [ NSTCSTYLE . NSTCS_DIMMEDCHECKBOXES ] = > ShellTreeItemCheckBoxStyle . Dimmed ,
var s when s [ NSTCSTYLE . NSTCS_CHECKBOXES ] = > ShellTreeItemCheckBoxStyle . Normal ,
_ = > ShellTreeItemCheckBoxStyle . None
} ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
set
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
var lstyle = ( ( NSTCSTYLE ) style ) . SetFlags ( NSTCSTYLE . NSTCS_CHECKBOXES | NSTCSTYLE . NSTCS_PARTIALCHECKBOXES | NSTCSTYLE . NSTCS_EXCLUSIONCHECKBOXES | NSTCSTYLE . NSTCS_DIMMEDCHECKBOXES , false ) |
value switch
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
ShellTreeItemCheckBoxStyle . Normal = > NSTCSTYLE . NSTCS_CHECKBOXES ,
ShellTreeItemCheckBoxStyle . Partial = > NSTCSTYLE . NSTCS_CHECKBOXES | NSTCSTYLE . NSTCS_PARTIALCHECKBOXES ,
ShellTreeItemCheckBoxStyle . Exclusion = > NSTCSTYLE . NSTCS_CHECKBOXES | NSTCSTYLE . NSTCS_EXCLUSIONCHECKBOXES ,
ShellTreeItemCheckBoxStyle . Dimmed = > NSTCSTYLE . NSTCS_CHECKBOXES | NSTCSTYLE . NSTCS_DIMMEDCHECKBOXES ,
_ = > 0
} ;
if ( style ! = lstyle )
{
style = lstyle ;
UpdateStyle ( ) ;
2020-02-12 22:36:39 -05:00
}
}
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Indicates whether to allow drag-and-drop operations within the control. Note that you can still drag an item from outside of the
/// control and drop it onto the control.
/// </summary>
[DefaultValue(false), Category("Behavior"), Description("Indicates whether to allow drag-and-drop operations within the control.")]
public bool DisableDragDrop
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_DISABLEDRAGDROP ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_DISABLEDRAGDROP , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Indicates whether to filter items based on the System.IsPinnedToNameSpaceTree value when INameSpaceTreeControlFolderCapabilities
/// is implemented.
/// </summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether to filter items based on their pinned value.")]
public bool DisplayPinnedItemsOnly
{
get = > HasTreeStyle ( NSTCSTYLE2 . NSTCS2_DISPLAYPINNEDONLY ) ;
set = > SetTreeStyle ( NSTCSTYLE2 . NSTCS2_DISPLAYPINNEDONLY , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Indicates whether to set the height of the items to an even height. By default, the height of items can be even or odd.
/// </summary>
[DefaultValue(false), Category("Appearance"), Description("Indicates whether to set the height of the items to an even height.")]
public bool ForceEvenHeight
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_EVENHEIGHT ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_EVENHEIGHT , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Indicates whether the selection of an item fills the row with inverse text to the end of the window area, regardless of the
/// length of the text. When this option is not declared, only the area behind text is inverted.
/// </summary>
[DefaultValue(true), Category("Appearance"), Description("Indicates whether the highlight spans the width of the control.")]
public bool FullRowSelect
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_FULLROWSELECT ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_FULLROWSELECT , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether the node of an item is not outlined when the control does not have the focus.</summary>
[DefaultValue(false), Category("Appearance"), Description("Removes highlight from the selected item when control does not have the focus.")]
public bool HideSelection
{
get = > ! HasTreeStyle ( NSTCSTYLE . NSTCS_SHOWSELECTIONALWAYS ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_SHOWSELECTIONALWAYS , ! value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// If the control does not have the focus and there are items that are preceded by expandos, then these expandos are visible only
/// when the mouse pointer is near to the control.
/// </summary>
[DefaultValue(true), Category("Appearance"), Description("Expandos are only visible when mouse hovers near the control.")]
public bool HotExpandos
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_FADEINOUTEXPANDOS ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_FADEINOUTEXPANDOS , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether to allow creation of an in-place edit box, which would allow the user to rename the given item.</summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether the user can edit the label text of items.")]
public bool LabelEdit
{
get = > ! HasTreeStyle ( NSTCSTYLE . NSTCS_NOEDITLABELS ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_NOEDITLABELS , ! value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether check boxes are located at the far left edge of the window area instead of being indented.</summary>
[DefaultValue(false), Category("Appearance"), Description("Removes indent before item check boxes.")]
public bool NoIndentCheckBoxes
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_NOINDENTCHECKS ) ;
set = > SetTreeStyle ( value ? NSTCSTYLE . NSTCS_NOINDENTCHECKS | NSTCSTYLE . NSTCS_CHECKBOXES : NSTCSTYLE . NSTCS_NOINDENTCHECKS , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the root items.</summary>
/// <value>The root items.</value>
[Browsable(false)]
public ShellNamespaceTreeRootList RootItems { get ; }
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets the currently selected item, or <see langword="null"/> if nothing is selected.</summary>
/// <value>The selected item, or <see langword="null"/> if nothing is selected.</value>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
2023-09-29 13:58:35 -04:00
public ShellItem ? SelectedItem
2023-03-31 11:47:53 -04:00
{
get
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
if ( pCtrl ! = null & & pCtrl . GetSelectedItems ( out var items ) . Succeeded )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
try { return ShellItem . Open ( items . GetItemAt ( 0 ) ) ; }
finally { Marshal . ReleaseComObject ( items ) ; }
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
return null ;
2020-02-12 22:36:39 -05:00
}
2023-09-29 13:58:35 -04:00
set = > SetItemState ( value , ( ShellTreeItemState ) NSTCITEMSTATE_ALL , GetItemState ( value ) | ShellTreeItemState . Selected ) ;
2023-03-31 11:47:53 -04:00
}
/// <summary>
/// Indicates which button to display on the right side of an item. The action associated with the button is implementation specific.
/// </summary>
[DefaultValue(ShellTreeItemButton.None), Category("Appearance"), Description("Indicates which button to display on the right side of an item.")]
public ShellTreeItemButton ShowFolderButton
{
get = > style switch
{
var s when s [ NSTCSTYLE . NSTCS_SHOWTABSBUTTON ] = > ShellTreeItemButton . Arrow ,
var s when s [ NSTCSTYLE . NSTCS_SHOWDELETEBUTTON ] = > ShellTreeItemButton . Delete ,
var s when s [ NSTCSTYLE . NSTCS_SHOWREFRESHBUTTON ] = > ShellTreeItemButton . Refresh ,
_ = > ShellTreeItemButton . None
} ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
set
2020-08-06 19:16:40 -04:00
{
2023-03-31 11:47:53 -04:00
var lstyle = ( ( NSTCSTYLE ) style ) . SetFlags ( NSTCSTYLE . NSTCS_SHOWTABSBUTTON | NSTCSTYLE . NSTCS_SHOWDELETEBUTTON | NSTCSTYLE . NSTCS_SHOWREFRESHBUTTON , false ) |
value switch
{
ShellTreeItemButton . Arrow = > NSTCSTYLE . NSTCS_SHOWTABSBUTTON ,
ShellTreeItemButton . Delete = > NSTCSTYLE . NSTCS_SHOWDELETEBUTTON ,
ShellTreeItemButton . Refresh = > NSTCSTYLE . NSTCS_SHOWREFRESHBUTTON ,
_ = > 0
} ;
if ( style ! = lstyle )
2020-08-06 19:16:40 -04:00
{
2023-03-31 11:47:53 -04:00
style = lstyle ;
UpdateStyle ( ) ;
2020-08-06 19:16:40 -04:00
}
}
2023-03-31 11:47:53 -04:00
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether to display infotips when the mouse cursor is over an item.</summary>
[DefaultValue(false), Category("Behavior"), Description("Indicates whether ToolTips will be displayed on the items.")]
public bool ShowItemToolTips
{
get = > ! HasTreeStyle ( NSTCSTYLE . NSTCS_NOINFOTIP ) ;
set
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
SetTreeStyle ( NSTCSTYLE . NSTCS_NOINFOTIP , ! value ) ;
if ( value )
SetTreeStyle ( NSTCSTYLE . NSTCS_RICHTOOLTIP , false ) ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether the control draws lines to the left of the tree items that lead to their individual parent items.</summary>
[DefaultValue(false), Category("Appearance"), Description("Indicates whether lines are displayed between sibling items and between parent and child items.")]
public bool ShowLines
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_HASLINES ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_HASLINES , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// If <see langword="true"/>, the control displays an indicator on the leftmost edge of those items that have child items. Clicking
/// on the indicator expands the item to reveal the children of the item.
/// </summary>
[DefaultValue(true), Category("Appearance"), Description("Indicates if plus/minus buttons will be shown next to parent nodes.")]
public bool ShowPlusMinus
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_HASEXPANDOS ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_HASEXPANDOS , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether the root item is preceded by an expando that allows expansion of the root item.</summary>
[DefaultValue(true), Category("Appearance"), Description("Indicates whether lines are display between root items.")]
public bool ShowRootLines
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_ROOTHASEXPANDO ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_ROOTHASEXPANDO , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Indicates whether an item expands to show its child items in response to a single mouse click.</summary>
[DefaultValue(false), Category("Behavior"), Description("Indicates whether an item expands to show its child items in response to a single mouse click.")]
public bool SingleClickExpand
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_SINGLECLICKEXPAND ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_SINGLECLICKEXPAND , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Indicates whether when one item is selected and expanded and you select a second item, the first selection automatically collapses.
/// </summary>
[DefaultValue(false), Category("Behavior"), Description("Indicates whether when one item is selected and expanded and you select a second item, the first selection automatically collapses.")]
public bool SpringExpand
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_SPRINGEXPAND ) ;
set = > SetTreeStyle ( NSTCSTYLE . NSTCS_SPRINGEXPAND , value ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>If the control is hosted, you can tabstop into the control.</summary>
[DefaultValue(true), Category("Behavior"), Description("Indicates whether the user can use the TAB key to gain access to the control.")]
public new bool TabStop
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_TABSTOP ) ;
set
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
if ( SetTreeStyle ( NSTCSTYLE . NSTCS_TABSTOP , value ) )
OnTabStopChanged ( EventArgs . Empty ) ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets or sets the desktop theme for the current control.</summary>
/// <value>The name of the desktop theme to which the current window is being set.</value>
[DefaultValue(null), Category("Appearance"), Description("Gets or sets the desktop theme for the current control.")]
2023-09-29 13:58:35 -04:00
public string? Theme { get = > theme ; set { theme = value ; pCtrl ? . SetTheme ( value ) ; } }
2023-03-31 11:47:53 -04:00
// TODO: Figure how to do this best
//[DefaultValue(false)]
//public bool Scrollable
//{
// get => HasTreeStyle(NSTCSTYLE.NSTCS_HORIZONTALSCROLL);
// set => SetTreeStyle(NSTCSTYLE.NSTCS_HORIZONTALSCROLL, value);
//}
//[DefaultValue(false)]
//public bool NoReplaceOpen
//{
// get => HasTreeStyle(NSTCSTYLE.NSTCS_NOREPLACEOPEN);
// set => SetTreeStyle(NSTCSTYLE.NSTCS_NOREPLACEOPEN, value);
//}
// TODO: Figure how to do this best
//[DefaultValue(false)]
//public bool AutoHScroll
//{
// get => HasTreeStyle(NSTCSTYLE.NSTCS_AUTOHSCROLL);
// set => SetTreeStyle(NSTCSTYLE.NSTCS_AUTOHSCROLL, value);
//}
/// <summary>
/// Indicates whether to use a rich tooltip. Rich tooltips display the item's icon in addition to the item's text. A standard
/// tooltip displays only the item's text. The tree view displays tooltips only for items in the tree that are partially visible.
/// </summary>
[DefaultValue(false), Category("Behavior"), Description("Indicates whether to use a rich tooltip.")]
public bool UseRichToolTips
{
get = > HasTreeStyle ( NSTCSTYLE . NSTCS_RICHTOOLTIP ) ;
set = > SetTreeStyle ( value ? NSTCSTYLE . NSTCS_RICHTOOLTIP | NSTCSTYLE . NSTCS_NOINFOTIP : NSTCSTYLE . NSTCS_RICHTOOLTIP , value ) ;
}
/// <summary>
/// Gets the required creation parameters when the control handle is created.
/// </summary>
protected override CreateParams CreateParams
{
get
2020-08-06 19:16:40 -04:00
{
2023-03-31 11:47:53 -04:00
var cp = base . CreateParams ;
if ( ! this . IsDesignMode ( ) )
2020-08-06 19:16:40 -04:00
{
2023-03-31 11:47:53 -04:00
cp . Style & = ~ ( int ) WindowStyles . WS_VISIBLE ;
2020-08-06 19:16:40 -04:00
}
2023-03-31 11:47:53 -04:00
return cp ;
2020-08-06 19:16:40 -04:00
}
2023-03-31 11:47:53 -04:00
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Collapses all of the items in the tree.</summary>
2023-09-29 13:58:35 -04:00
public void CollapseAll ( ) = > pCtrl ? . CollapseAll ( ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Ensures that the given item is visible.</summary>
/// <param name="item">The Shell item for which the visibility is being ensured.</param>
2023-09-29 13:58:35 -04:00
public void EnsureVisible ( ShellItem item ) = > pCtrl ? . EnsureItemVisible ( item . IShellItem ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets state information about a Shell item.</summary>
/// <param name="item">A pointer to the Shell item from which to retrieve the state.</param>
/// <returns>The state of the specified item.</returns>
2023-09-29 13:58:35 -04:00
public ShellTreeItemState GetItemState ( ShellItem ? item ) = > pCtrl is not null & & item is not null & & pCtrl . GetItemState ( item . IShellItem , NSTCITEMSTATE_ALL , out var state ) . Succeeded ? ( ShellTreeItemState ) state : 0 ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Retrieves the item that a given point is in, if any.</summary>
/// <param name="pt">The point to be tested.</param>
/// <returns>The item in which the point exists, or <see langword="null"/> if the point does not exist in an item.</returns>
2023-09-29 13:58:35 -04:00
public ShellItem ? HitTest ( Point pt )
2023-03-31 11:47:53 -04:00
{
2023-09-29 13:58:35 -04:00
IShellItem ? psi = null ;
pCtrl ? . HitTest ( pt , out psi ) ;
2023-03-31 11:47:53 -04:00
return psi is null ? null : ShellItem . Open ( psi ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Sets state information for a Shell item.</summary>
/// <param name="item">
/// <para>The Shell item for which to set the state.</para>
/// </param>
/// <param name="stateMask">
/// <para>Specifies which information is being set, in the form of a bitmap.</para>
/// </param>
/// <param name="state">
/// <para>A bitmap that contains the values to set for the flags specified in <paramref name="stateMask"/>.</para>
/// </param>
/// <remarks>
/// The <paramref name="stateMask"/> value specifies which bits in the value pointed to by <paramref name="state"/> are to be set.
/// Other bits are ignored. As a simple example, if <paramref name="stateMask"/>=Selected, then the first bit in the <paramref
/// name="state"/> value determines whether that flag is set (1) or removed (0).
/// </remarks>
2023-09-29 13:58:35 -04:00
public void SetItemState ( ShellItem ? item , ShellTreeItemState stateMask , ShellTreeItemState state ) { if ( item is not null ) pCtrl ? . SetItemState ( item . IShellItem , ( NSTCITEMSTATE ) stateMask , ( NSTCITEMSTATE ) state ) ; }
2023-03-31 11:47:53 -04:00
bool IMessageFilter . PreFilterMessage ( ref Message m )
{
2023-09-29 13:58:35 -04:00
if ( m . Msg is ( ( int ) WindowMessage . WM_KEYDOWN ) or ( ( int ) WindowMessage . WM_KEYUP ) )
2023-03-31 11:47:53 -04:00
Debug . WriteLine ( $"PreFileter msg: {(WindowMessage)m.Msg}, {(Keys)unchecked((int)(long)m.WParam)}" ) ;
return ( pCtrl as ExplorerBrowser . IInputObject_WinForms ) ? . TranslateAcceleratorIO ( m ) = = HRESULT . S_OK ;
}
2020-08-06 19:16:40 -04:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlEvents . OnAfterContextMenu ( IShellItem ? psi , IContextMenu pcmIn , in Guid riid , out object? ppv )
2023-03-31 11:47:53 -04:00
{
if ( riid = = typeof ( IContextMenu ) . GUID )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
// TODO: Figure out how to host ContextMenuStrip
//if (ContextMenuStrip != null)
//{
// var ictxmenu = new IContextMenu();
// ppv = ContextMenuStrip.; /* get IContextMenu from ContextMenuStrip */
// return HRESULT.S_OK;
//}
ppv = pcmIn ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
else
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
ppv = default ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
return HRESULT . E_NOTIMPL ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnAfterExpand ( IShellItem psi )
{
AfterExpand ? . Invoke ( this , new ShellNamespaceTreeControlEventArgs ( psi , ShellNamespaceTreeControlAction . Expand ) ) ;
return HRESULT . S_OK ;
}
2020-02-12 22:36:39 -05:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlEvents . OnBeforeContextMenu ( IShellItem ? psi , in Guid riid , out object? ppv )
2023-03-31 11:47:53 -04:00
{
if ( riid = = typeof ( IContextMenu ) . GUID )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
ppv = default ; // TODO: replace with result from event
return HRESULT . E_NOTIMPL ; // Change if menu provided by event
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
else
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
ppv = default ;
return HRESULT . E_NOTIMPL ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnBeforeExpand ( IShellItem psi )
{
var args = new ShellNamespaceTreeControlCancelEventArgs ( psi , false , ShellNamespaceTreeControlAction . Expand ) ;
try { BeforeExpand ? . Invoke ( this , args ) ; } catch ( Exception ex ) { return HRESULT . FromException ( ex ) ; }
return args . Cancel ? HRESULT . S_FALSE : HRESULT . S_OK ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnBeforeItemDelete ( IShellItem psi )
{
var args = new ShellNamespaceTreeControlCancelEventArgs ( psi , false , ShellNamespaceTreeControlAction . BeforeDelete ) ;
BeforeItemDelete ? . Invoke ( this , args ) ;
return args . Cancel ? HRESULT . S_FALSE : HRESULT . S_OK ;
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnBeforeStateImageChange ( IShellItem psi ) = > HRESULT . S_OK ;
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnBeginLabelEdit ( IShellItem psi )
{
BeforeLabelEdit ? . Invoke ( this , new ShellNamespaceTreeControlItemLabelEditEventArgs ( psi ) ) ;
return HRESULT . S_OK ;
}
2020-08-06 19:16:40 -04:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlDropHandler . OnDragEnter ( IShellItem ? psiOver , IShellItemArray psiaData , bool fOutsideSource , uint grfKeyState , ref uint pdwEffect )
2023-03-31 11:47:53 -04:00
{
var ido = new DataObject ( ) ;
ido . SetFileDropList ( GetStringCollection ( psiaData ) ) ;
var dragEvent = new DragEventArgs ( ido , ( int ) grfKeyState , MousePosition . X , MousePosition . Y , DragDropEffects . All , ( DragDropEffects ) pdwEffect ) ;
base . OnDragEnter ( dragEvent ) ;
pdwEffect = ( uint ) dragEvent . Effect ;
return HRESULT . S_OK ;
}
2020-08-06 19:16:40 -04:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlDropHandler . OnDragLeave ( IShellItem ? psiOver )
2023-03-31 11:47:53 -04:00
{
base . OnDragLeave ( EventArgs . Empty ) ;
return HRESULT . S_OK ;
}
2020-08-06 19:16:40 -04:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlDropHandler . OnDragOver ( IShellItem ? psiOver , IShellItemArray psiaData , uint grfKeyState , ref uint pdwEffect )
2023-03-31 11:47:53 -04:00
{
var ido = new DataObject ( ) ;
ido . SetFileDropList ( GetStringCollection ( psiaData ) ) ;
var dragEvent = new DragEventArgs ( ido , ( int ) grfKeyState , MousePosition . X , MousePosition . Y , DragDropEffects . All , ( DragDropEffects ) pdwEffect ) ;
base . OnDragOver ( dragEvent ) ;
pdwEffect = ( uint ) dragEvent . Effect ;
return HRESULT . S_OK ;
}
2020-02-12 22:36:39 -05:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlDropHandler . OnDragPosition ( IShellItem ? psiOver , IShellItemArray psiaData , int iNewPosition , int iOldPosition ) = > HRESULT . E_FAIL ;
2020-08-06 19:16:40 -04:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlDropHandler . OnDrop ( IShellItem ? psiOver , IShellItemArray psiaData , int iPosition , uint grfKeyState , ref uint pdwEffect )
2023-03-31 11:47:53 -04:00
{
var ido = new DataObject ( ) ;
ido . SetFileDropList ( GetStringCollection ( psiaData ) ) ;
var dragEvent = new DragEventArgs ( ido , ( int ) grfKeyState , MousePosition . X , MousePosition . Y , DragDropEffects . All , ( DragDropEffects ) pdwEffect ) ;
base . OnDragDrop ( dragEvent ) ;
pdwEffect = ( uint ) dragEvent . Effect ;
return HRESULT . S_OK ;
}
2020-02-12 22:36:39 -05:00
2023-09-29 13:58:35 -04:00
HRESULT INameSpaceTreeControlDropHandler . OnDropPosition ( IShellItem ? psiOver , IShellItemArray psiaData , int iNewPosition , int iOldPosition ) = > HRESULT . E_FAIL ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnEndLabelEdit ( IShellItem psi )
{
AfterLabelEdit ? . Invoke ( this , new ShellNamespaceTreeControlItemLabelEditEventArgs ( psi ) ) ;
return HRESULT . S_OK ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnGetDefaultIconIndex ( IShellItem psi , out int piDefaultIcon , out int piOpenIcon )
{
piDefaultIcon = piOpenIcon = default ;
return HRESULT . E_NOTIMPL ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnGetToolTip ( IShellItem psi , StringBuilder pszTip , int cchTip ) = > HRESULT . E_NOTIMPL ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnItemAdded ( IShellItem psi , bool fIsRoot )
{
AfterItemAdd ? . Invoke ( this , new ShellNamespaceTreeControlEventArgs ( psi , ShellNamespaceTreeControlAction . AfterAdd ) ) ;
return HRESULT . E_NOTIMPL ;
//return HRESULT.S_OK;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnItemClick ( IShellItem psi , NSTCEHITTEST nstceHitTest , NSTCECLICKTYPE nstceClickType )
{
var mb = MouseButtons . None ;
switch ( nstceClickType )
{
case NSTCECLICKTYPE . NSTCECT_LBUTTON :
mb = MouseButtons . Left ;
break ;
case NSTCECLICKTYPE . NSTCECT_MBUTTON :
mb = MouseButtons . Middle ;
break ;
case NSTCECLICKTYPE . NSTCECT_RBUTTON :
mb = MouseButtons . Right ;
break ;
}
var args = new ShellNamespaceTreeControlItemMouseClickEventArgs ( psi , mb , nstceHitTest ) ;
if ( nstceClickType > NSTCECLICKTYPE . NSTCECT_BUTTON )
ItemMouseDoubleClick ? . Invoke ( this , args ) ;
else
ItemMouseClick ? . Invoke ( this , args ) ;
return args . Handled ? HRESULT . S_OK : HRESULT . S_FALSE ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnItemDeleted ( IShellItem psi , bool fIsRoot )
{
AfterItemDelete ? . Invoke ( this , new ShellNamespaceTreeControlEventArgs ( psi , ShellNamespaceTreeControlAction . AfterDelete ) ) ;
return HRESULT . E_NOTIMPL ;
//return HRESULT.S_OK;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnItemStateChanged ( IShellItem psi , NSTCITEMSTATE nstcisMask , NSTCITEMSTATE nstcisState ) = > HRESULT . S_OK ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnItemStateChanging ( IShellItem psi , NSTCITEMSTATE nstcisMask , NSTCITEMSTATE nstcisState ) = > HRESULT . S_OK ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnKeyboardInput ( uint uMsg , IntPtr wParam , IntPtr lParam )
{
2023-08-04 12:24:49 -04:00
Debug . WriteLine ( $"Kbd msg: {(WindowMessage)uMsg}, {(Keys)unchecked((int)(long)wParam)}" ) ;
2023-03-31 11:47:53 -04:00
//var args = new KeyEventArgs((Keys)unchecked((int)(long)wParam) | ModifierKeys);
var hSel = SendMessage ( hWndTreeView , ComCtl32 . TreeViewMessage . TVM_GETNEXTITEM , ComCtl32 . TreeViewActionFlag . TVGN_CARET ) ;
if ( hSel ! = default & & uMsg = = ( uint ) WindowMessage . WM_KEYUP )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
switch ( ( Keys ) unchecked ( ( int ) ( long ) wParam ) )
2020-08-06 19:16:40 -04:00
{
2023-03-31 11:47:53 -04:00
case Keys . Down :
//Move(IsExpanded(hSel) ? ComCtl32.TreeViewActionFlag.TVGN_CHILD : ComCtl32.TreeViewActionFlag.TVGN_NEXT);
Move ( ComCtl32 . TreeViewActionFlag . TVGN_NEXTVISIBLE ) ;
break ;
case Keys . Up :
//var hPrev = SendMessage(hWndTreeView, ComCtl32.TreeViewMessage.TVM_GETNEXTITEM, ComCtl32.TreeViewActionFlag.TVGN_PREVIOUS, hSel);
//if (hPrev != default)
//{
// if (IsExpanded(hPrev))
// Move(ComCtl32.TreeViewActionFlag.TVGN_PREVIOUSVISIBLE);
// else
// SelItem(hPrev);
//}
Move ( ComCtl32 . TreeViewActionFlag . TVGN_PREVIOUSVISIBLE ) ;
break ;
case Keys . Right :
if ( IsExpanded ( hSel ) )
Move ( ComCtl32 . TreeViewActionFlag . TVGN_CHILD ) ;
else
SendMessage ( hWndTreeView , ComCtl32 . TreeViewMessage . TVM_EXPAND , ComCtl32 . TreeViewExpandFlags . TVE_EXPAND , hSel ) ;
break ;
case Keys . Left :
if ( IsExpanded ( hSel ) )
SendMessage ( hWndTreeView , ComCtl32 . TreeViewMessage . TVM_EXPAND , ComCtl32 . TreeViewExpandFlags . TVE_COLLAPSE , hSel ) ;
else
Move ( ComCtl32 . TreeViewActionFlag . TVGN_PARENT ) ;
break ;
case Keys . Home :
Move ( ComCtl32 . TreeViewActionFlag . TVGN_ROOT ) ;
break ;
case Keys . End :
Move ( ComCtl32 . TreeViewActionFlag . TVGN_LASTVISIBLE ) ;
break ;
case Keys . Enter :
break ;
case Keys . Space :
break ;
2020-08-06 19:16:40 -04:00
}
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
//if (uMsg == (uint)WindowMessage.WM_KEYUP)
// OnKeyUp(args);
//return args.Handled ? HRESULT.S_FALSE : HRESULT.S_OK;
return HRESULT . S_FALSE ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
bool IsExpanded ( IntPtr item ) = > SendMessage ( hWndTreeView , ( uint ) ComCtl32 . TreeViewMessage . TVM_GETITEMSTATE , item , ( IntPtr ) ( int ) ComCtl32 . TreeViewItemStates . TVIS_EXPANDED ) = = ( IntPtr ) ( int ) ComCtl32 . TreeViewItemStates . TVIS_EXPANDED ;
2020-02-12 22:36:39 -05:00
2023-09-29 13:58:35 -04:00
void Move ( ComCtl32 . TreeViewActionFlag dir ) = > SelItem ( SendMessage ( hWndTreeView , ComCtl32 . TreeViewMessage . TVM_GETNEXTITEM , dir , hSel ) ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
void SelItem ( IntPtr hNext )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
if ( hNext ! = default )
SendMessage ( hWndTreeView , ComCtl32 . TreeViewMessage . TVM_SELECTITEM , ComCtl32 . TreeViewActionFlag . TVGN_CARET , hNext ) ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnPropertyItemCommit ( IShellItem psi ) = > HRESULT . S_FALSE ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
HRESULT INameSpaceTreeControlEvents . OnSelectionChanged ( IShellItemArray psiaSelection )
{
OnAfterSelect ( ) ;
return HRESULT . S_OK ;
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
HRESULT Shell32 . IServiceProvider . QueryService ( in Guid guidService , in Guid riid , out IntPtr ppvObject )
{
if ( riid = = typeof ( INameSpaceTreeControlDropHandler ) . GUID )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
ppvObject = Marshal . GetComInterfaceForObject ( this , typeof ( INameSpaceTreeControlDropHandler ) ) ; ;
return HRESULT . S_OK ;
2020-08-06 19:16:40 -04:00
}
2023-03-31 11:47:53 -04:00
else if ( riid = = typeof ( INameSpaceTreeControlEvents ) . GUID )
2020-08-06 19:16:40 -04:00
{
2023-03-31 11:47:53 -04:00
ppvObject = Marshal . GetComInterfaceForObject ( this , typeof ( INameSpaceTreeControlEvents ) ) ; ;
return HRESULT . S_OK ;
2020-08-06 19:16:40 -04:00
}
2023-03-31 11:47:53 -04:00
ppvObject = default ;
return HRESULT . E_NOINTERFACE ;
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Releases unmanaged and - optionally - managed resources.</summary>
/// <param name="disposing">
/// <see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.
/// </param>
protected override void Dispose ( bool disposing )
{
base . Dispose ( disposing ) ;
2023-08-04 12:24:49 -04:00
if ( oleUninit ) OleUninitialize ( ) ;
2023-03-31 11:47:53 -04:00
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Raises the <see cref="AfterSelect"/> event.</summary>
protected virtual void OnAfterSelect ( ) = > AfterSelect ? . Invoke ( this , EventArgs . Empty ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Raises the <see cref="M:System.Windows.Forms.Control.CreateControl"/> method.</summary>
protected override void OnCreateControl ( )
{
base . OnCreateControl ( ) ;
if ( this . IsDesignMode ( ) ) return ;
// Grab interfaces
pCtrl = new INameSpaceTreeControl ( ) ;
pCtrl2 = pCtrl as INameSpaceTreeControl2 ;
// Initialize and capture child window handles
var rect = BorderStyle = = BorderStyle . None ? Bounds : Rectangle . Inflate ( Bounds , - 1 , - 1 ) ;
2023-12-30 19:50:35 -05:00
pCtrl . Initialize ( Parent ! . Handle , rect , style ) . ThrowIfFailed ( ) ;
2023-03-31 11:47:53 -04:00
var sb = new StringBuilder ( 512 ) ;
var srect = ( RECT ) RectangleToScreen ( rect ) ;
hWndNsTreeCtrl = User32 . EnumChildWindows ( Parent . Handle ) . First ( h = > IsClass ( h , "NamespaceTreeControl" ) ) ;
hWndTreeView = hWndNsTreeCtrl . EnumChildWindows ( ) . First ( h = > IsClass ( h , "SysTreeView32" ) ) ;
// Remove default roots and update style
pCtrl . RemoveAllRoots ( ) ;
UpdateStyle ( ) ;
// Setup event handler and sink
pCtrl . TreeAdvise ( this , out adviseCookie ) . ThrowIfFailed ( ) ;
SetSite ( this ) ;
Application . AddMessageFilter ( this ) ;
bool IsClass ( HWND hWnd , string className ) = >
GetClassName ( hWnd , sb , sb . Capacity ) > 0 & & sb . ToString ( ) = = className & & GetWindowRect ( hWnd , out var r ) & & r = = srect ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Raises the <see cref="E:System.Windows.Forms.Control.GotFocus"/> event.</summary>
/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnGotFocus ( EventArgs e )
{
base . OnGotFocus ( e ) ;
if ( ! hWndTreeView . IsNull )
SetFocus ( hWndTreeView ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Raises the <see cref="E:System.Windows.Forms.Control.KeyDown"/> event.</summary>
/// <param name="e">A <see cref="T:System.Windows.Forms.KeyEventArgs"/> that contains the event data.</param>
protected override void OnKeyDown ( KeyEventArgs e )
{
2023-08-04 12:24:49 -04:00
Debug . WriteLine ( $"Base KeyDown: {e.KeyCode}" ) ;
2023-03-31 11:47:53 -04:00
base . OnKeyDown ( e ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Raises the <see cref="E:System.Windows.Forms.Control.KeyUp"/> event.</summary>
/// <param name="e">A <see cref="T:System.Windows.Forms.KeyEventArgs"/> that contains the event data.</param>
protected override void OnKeyUp ( KeyEventArgs e )
{
2023-08-04 12:24:49 -04:00
Debug . WriteLine ( $"Base KeyUp: {e.KeyCode}" ) ;
2023-03-31 11:47:53 -04:00
base . OnKeyUp ( e ) ;
}
/// <summary>Raises the <see cref="E:HandleDestroyed"/> event.</summary>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected override void OnHandleDestroyed ( EventArgs e )
{
if ( pCtrl ! = null )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
if ( adviseCookie > 0 )
pCtrl . TreeUnadvise ( adviseCookie ) ;
SetSite ( null ) ;
pCtrl = null ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
pCtrl2 = null ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
base . OnHandleDestroyed ( e ) ;
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Raises the <see cref="E:Paint"/> event.</summary>
/// <param name="e">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
protected override void OnPaint ( PaintEventArgs e )
{
base . OnPaint ( e ) ;
if ( borderStyle ! = BorderStyle . None )
ControlPaint . DrawBorder3D ( e . Graphics , Bounds , Border3DStyle . Flat ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Raises the <see cref="E:SizeChanged"/> event.</summary>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected override void OnSizeChanged ( EventArgs e )
{
base . OnSizeChanged ( e ) ;
SetWindowPos ( hWndNsTreeCtrl , HWND . NULL , Left , Top , Width , Height , SetWindowPosFlags . SWP_NOACTIVATE | SetWindowPosFlags . SWP_NOOWNERZORDER | SetWindowPosFlags . SWP_NOZORDER ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Enables a container to pass an object a pointer to the interface for its site.</summary>
/// <param name="sp">
/// A pointer to the <c>IServiceProvider</c> interface pointer of the site managing this object. If <see langword="null"/>, the
/// object should call Release on any existing site at which point the object no longer knows its site.
/// </param>
2023-09-29 13:58:35 -04:00
protected virtual void SetSite ( Shell32 . IServiceProvider ? sp ) = > ( pCtrl as IObjectWithSite ) ? . SetSite ( sp ) ;
2023-03-31 11:47:53 -04:00
private static System . Collections . Specialized . StringCollection GetStringCollection ( IShellItemArray psiaData )
{
using var shiArray = new ShellItemArray ( psiaData ) ;
var fileList = new System . Collections . Specialized . StringCollection ( ) ;
2023-09-29 13:58:35 -04:00
fileList . AddRange ( shiArray . Select ( shi = > shi . ParsingName ) . WhereNotNull ( ) . ToArray ( ) ) ;
2023-03-31 11:47:53 -04:00
return fileList ;
}
private IEnumerable < IShellItem > EnumVisibleItems ( )
{
2023-09-29 13:58:35 -04:00
if ( pCtrl is null ) yield break ;
2023-03-31 11:47:53 -04:00
var hr = pCtrl . GetNextItem ( null , NSTCGNI . NSTCGNI_FIRSTVISIBLE , out var psi ) ;
while ( hr . Succeeded )
2020-02-12 22:36:39 -05:00
{
2023-09-29 13:58:35 -04:00
yield return psi ! ;
2023-03-31 11:47:53 -04:00
hr = pCtrl . GetNextItem ( psi , NSTCGNI . NSTCGNI_NEXTVISIBLE , out psi ) ;
2020-02-12 22:36:39 -05:00
}
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
private bool HasTreeStyle ( NSTCSTYLE style ) = > this . style [ style ] ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
private bool HasTreeStyle ( NSTCSTYLE2 style ) = > style2 [ style ] ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
private bool SetTreeStyle ( NSTCSTYLE style , bool value )
{
if ( HasTreeStyle ( style ) = = value ) return false ;
this . style [ style ] = value ;
UpdateStyle ( ) ;
return true ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
private void SetTreeStyle ( NSTCSTYLE2 style , bool value )
{
if ( HasTreeStyle ( style ) = = value ) return ;
style2 [ style ] = value ;
UpdateStyle ( ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
private void UpdateStyle ( )
{
2023-09-29 13:58:35 -04:00
if ( pCtrl is null | | ! IsHandleCreated ) return ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
// Set styles
pCtrl2 ? . SetControlStyle ( NSTCSTYLE_ALL , style ) ;
pCtrl2 ? . SetControlStyle2 ( NSTCSTYLE2_ALL , style2 ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
// Get the current root items and states of visible items
var states = EnumVisibleItems ( ) . Select ( i = > ( i , GetState ( i ) ) ) . Where ( t = > t . Item2 ! = NSTCITEMSTATE . NSTCIS_NONE ) . ToList ( ) ;
2020-07-01 17:04:47 -04:00
2023-03-31 11:47:53 -04:00
// Reset the list (required to refresh)
RootItems . SyncWithParent ( ) ;
2020-07-01 17:04:47 -04:00
2023-03-31 11:47:53 -04:00
// Add back all roots and their states
foreach ( var ( i , state , num , childOnly ) in RootItems . Select ( i = > ( i , GetState ( i . IShellItem ) , pCtrl . GetItemCustomState ( i . IShellItem , out var num ) . Succeeded ? num : 0 , RootItems . onlyShowChildren [ i ] ) ) )
2020-07-01 17:04:47 -04:00
{
2023-03-31 11:47:53 -04:00
//RootItems.Add(i, childOnly, state.IsFlagSet(NSTCITEMSTATE.NSTCIS_EXPANDED));
if ( state ! = NSTCITEMSTATE . NSTCIS_NONE )
pCtrl . SetItemState ( i . IShellItem , NSTCITEMSTATE_ALL , state ) ;
if ( num ! = 0 )
pCtrl . SetItemCustomState ( i . IShellItem , num ) ;
2020-07-01 17:04:47 -04:00
}
2023-03-31 11:47:53 -04:00
// Add back all states for visible items
foreach ( var ( i , state ) in states )
pCtrl . SetItemState ( i , NSTCITEMSTATE_ALL , state ) ;
2020-07-01 17:04:47 -04:00
2023-03-31 11:47:53 -04:00
NSTCITEMSTATE GetState ( IShellItem shi ) = > pCtrl . GetItemState ( shi , NSTCITEMSTATE_ALL , out var state ) . Succeeded ? state : 0 ;
}
//HRESULT INameSpaceTreeAccessible.OnGetDefaultAccessibilityAction(IShellItem psi, out string pbstrDefaultAction) => throw new NotImplementedException();
//HRESULT INameSpaceTreeAccessible.OnDoDefaultAccessibilityAction(IShellItem psi) => throw new NotImplementedException();
//HRESULT INameSpaceTreeAccessible.OnGetAccessibilityRole(IShellItem psi, out object pvarRole) => throw new NotImplementedException();
}
2020-07-01 17:04:47 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Provides data for the BeforeExpand, and BeforeSelect events of a <see cref="ShellNamespaceTreeControl"/> control.</summary>
/// <seealso cref="CancelEventArgs"/>
public class ShellNamespaceTreeControlCancelEventArgs : CancelEventArgs
{
/// <summary>Initializes a new instance of the <see cref="ShellNamespaceTreeControlEventArgs"/> class.</summary>
/// <param name="shellItem">The shell item instance.</param>
/// <param name="cancel"><see langword="true"/> to cancel the event; otherwise, <see langword="false"/>.</param>
/// <param name="action">The action performed.</param>
2023-09-29 13:58:35 -04:00
public ShellNamespaceTreeControlCancelEventArgs ( ShellItem ? shellItem , bool cancel , ShellNamespaceTreeControlAction action ) : base ( cancel )
2023-03-31 11:47:53 -04:00
{
Item = shellItem ;
Action = action ;
2020-02-12 22:36:39 -05:00
}
2023-09-29 13:58:35 -04:00
internal ShellNamespaceTreeControlCancelEventArgs ( IShellItem ? psi , bool cancel , ShellNamespaceTreeControlAction action ) :
2023-03-31 11:47:53 -04:00
this ( psi is null ? null : ShellItem . Open ( psi ) , cancel , action )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The action associated with this event.</summary>
2023-09-29 13:58:35 -04:00
public ShellNamespaceTreeControlAction ? Action { get ; }
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The shell item associated with this event.</summary>
2023-09-29 13:58:35 -04:00
public ShellItem ? Item { get ; }
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Event arguments for actions against <see cref="ShellNamespaceTreeControl"/>.</summary>
/// <seealso cref="EventArgs"/>
public class ShellNamespaceTreeControlEventArgs : EventArgs
{
/// <summary>Initializes a new instance of the <see cref="ShellNamespaceTreeControlEventArgs"/> class.</summary>
/// <param name="shellItem">The shell item instance.</param>
/// <param name="action">The action performed.</param>
2023-09-29 13:58:35 -04:00
public ShellNamespaceTreeControlEventArgs ( ShellItem ? shellItem , ShellNamespaceTreeControlAction action )
2023-03-31 11:47:53 -04:00
{
Item = shellItem ;
Action = action ;
2020-02-12 22:36:39 -05:00
}
2023-09-29 13:58:35 -04:00
internal ShellNamespaceTreeControlEventArgs ( IShellItem ? psi , ShellNamespaceTreeControlAction action )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
Item = psi is null ? null : ShellItem . Open ( psi ) ;
Action = action ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The action associated with this event.</summary>
2023-09-29 13:58:35 -04:00
public ShellNamespaceTreeControlAction ? Action { get ; }
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The shell item associated with this event.</summary>
2023-09-29 13:58:35 -04:00
public ShellItem ? Item { get ; }
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Arguments for item label edit events in a <see cref="ShellNamespaceTreeControl"/>.</summary>
/// <seealso cref="EventArgs"/>
public class ShellNamespaceTreeControlItemLabelEditEventArgs : EventArgs
{
/// <summary>Initializes a new instance of the <see cref="ShellNamespaceTreeControlItemLabelEditEventArgs"/> class.</summary>
/// <param name="shellItem">The shell item.</param>
2023-09-29 13:58:35 -04:00
public ShellNamespaceTreeControlItemLabelEditEventArgs ( ShellItem ? shellItem ) = > Item = shellItem ;
2020-02-12 22:36:39 -05:00
2023-09-29 13:58:35 -04:00
internal ShellNamespaceTreeControlItemLabelEditEventArgs ( IShellItem ? psi ) = > Item = psi is null ? null : ShellItem . Open ( psi ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>On return, set to <see langword="true"/> to cancel the edit.</summary>
public bool CancelEdit { get ; set ; }
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The shell item associated with this event.</summary>
2023-09-29 13:58:35 -04:00
public ShellItem ? Item { get ; }
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The label associated with the selected item.</summary>
2023-09-29 13:58:35 -04:00
public string? Label = > Item ? . Name ;
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Arguments for mouse click events in a <see cref="ShellNamespaceTreeControl"/>.</summary>
public class ShellNamespaceTreeControlItemMouseClickEventArgs : HandledMouseEventArgs
{
internal ShellNamespaceTreeControlItemMouseClickEventArgs ( IShellItem item , MouseButtons button , NSTCEHITTEST ht )
: base ( button , 1 , 0 , 0 , 0 )
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
Item = ShellItem . Open ( item ) ;
HitLocation = ( ItemHitLocation ) ht ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The location of the item that has been clicked.</summary>
public ItemHitLocation HitLocation { get ; }
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>The shell item associated with this event.</summary>
public ShellItem Item { get ; }
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Encapsulates the list of root items in a <see cref="ShellNamespaceTreeControl"/>.</summary>
public class ShellNamespaceTreeRootList : IList < ShellItem >
{
2023-09-24 17:26:46 -04:00
internal Dictionary < ShellItem , bool > onlyShowChildren = new ( ) ;
2023-03-31 11:47:53 -04:00
internal ShellNamespaceTreeRootList ( ShellNamespaceTreeControl parent ) = > Parent = parent ;
/// <summary>Gets the number of elements contained in the <see cref="ICollection{ShellItem}"/>.</summary>
public int Count = > onlyShowChildren . Count ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Gets a value indicating whether this instance is read only.</summary>
/// <value><see langword="true"/> if this instance is read only; otherwise, <see langword="false"/>.</value>
bool ICollection < ShellItem > . IsReadOnly = > false ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
private ShellNamespaceTreeControl Parent { get ; }
/// <summary>Gets or sets the <see cref="ShellItem"/> at the specified index.</summary>
/// <value>The <see cref="ShellItem"/>.</value>
/// <param name="index">The index.</param>
/// <returns>A <see cref="ShellItem"/> instance.</returns>
public ShellItem this [ int index ]
{
get = > GetItemArray ( ) [ index ] ;
set
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
if ( index = = Count )
Add ( value , false , false ) ;
else
2020-02-12 22:36:39 -05:00
{
2023-03-31 11:47:53 -04:00
( ( IList < ShellItem > ) this ) . RemoveAt ( index ) ;
Insert ( index , value , false , false ) ;
2020-02-12 22:36:39 -05:00
}
}
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Appends a Shell item to the list of roots in a tree.</summary>
/// <param name="item">The Shell item to append.</param>
/// <param name="showChildrenOnly">The root is hidden so that the children only are visible. Mutually exclusive with NSTCRS_VISIBLE.</param>
/// <param name="expanded">The root is expanded upon initialization.</param>
public void Add ( ShellItem item , bool showChildrenOnly , bool expanded )
{
2023-09-29 13:58:35 -04:00
Parent . pCtrl ? . AppendRoot ( item . IShellItem , item . IsFolder ? SHCONTF . SHCONTF_FOLDERS : SHCONTF . SHCONTF_NONFOLDERS ,
2023-03-31 11:47:53 -04:00
( expanded ? NSTCROOTSTYLE . NSTCRS_EXPANDED : 0 ) | ( showChildrenOnly ? NSTCROOTSTYLE . NSTCRS_HIDDEN : NSTCROOTSTYLE . NSTCRS_VISIBLE ) ) ;
onlyShowChildren [ item ] = showChildrenOnly ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Removes all items from this list.</summary>
public void Clear ( )
{
2023-09-29 13:58:35 -04:00
Parent . pCtrl ? . RemoveAllRoots ( ) ;
2023-03-31 11:47:53 -04:00
onlyShowChildren . Clear ( ) ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>
/// Copies the elements of the <see cref="ICollection{ShellItem}"/> to an <see cref="T:System.Array"/>, starting at a particular
/// <see cref="Array"/> index.
/// </summary>
/// <param name="array">
/// The one-dimensional <see cref="Array"/> that is the destination of the elements copied from <see
/// cref="ICollection{ShellItem}"/>. The <see cref="Array"/> must have zero-based indexing.
/// </param>
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param>
public void CopyTo ( ShellItem [ ] array , int arrayIndex ) = > onlyShowChildren . Keys . CopyTo ( array , arrayIndex ) ;
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>A <see cref="IEnumerator{ShellItem}"/> that can be used to iterate through the collection.</returns>
public IEnumerator < ShellItem > GetEnumerator ( ) = > onlyShowChildren . Keys . GetEnumerator ( ) ;
/// <summary>Searches for the specified object and returns the zero-based index of the first occurrence within the entire list.</summary>
/// <param name="item">The object to locate in the list. The value can be <see langword="null"/> for reference types.</param>
/// <returns>The zero-based index of the first occurrence of item within the entire list, if found; otherwise, -1.</returns>
public int IndexOf ( ShellItem item ) = > onlyShowChildren . Keys . ToList ( ) . FindIndex ( i = > i . Equals ( item ) ) ;
/// <summary>Inserts a Shell item to the list of roots in a tree.</summary>
/// <param name="index">The index at which to insert the root.</param>
/// <param name="item">The Shell item to append.</param>
/// <param name="showChildrenOnly">The root is hidden so that the children only are visible. Mutually exclusive with NSTCRS_VISIBLE.</param>
/// <param name="expanded">The root is expanded upon initialization.</param>
public void Insert ( int index , ShellItem item , bool showChildrenOnly , bool expanded )
{
2023-09-29 13:58:35 -04:00
Parent . pCtrl ? . InsertRoot ( index , item . IShellItem , item . IsFolder ? SHCONTF . SHCONTF_FOLDERS : SHCONTF . SHCONTF_NONFOLDERS ,
2023-03-31 11:47:53 -04:00
( expanded ? NSTCROOTSTYLE . NSTCRS_EXPANDED : 0 ) | ( showChildrenOnly ? NSTCROOTSTYLE . NSTCRS_HIDDEN : NSTCROOTSTYLE . NSTCRS_VISIBLE ) ) ;
onlyShowChildren [ item ] = showChildrenOnly ;
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Removes the first occurrence of a specific object from the list.</summary>
/// <param name="item">The object to remove from the list. The value can be <see langword="null"/> for reference types.</param>
/// <returns>
/// <see langword="true"/> if item is successfully removed; otherwise, <see langword="false"/>. This method also returns <see
/// langword="false"/> if item was not found in the list.
/// </returns>
public bool Remove ( ShellItem item )
{
onlyShowChildren . Remove ( item ) ;
2023-09-29 13:58:35 -04:00
return Parent . pCtrl ? . RemoveRoot ( item . IShellItem ) . Succeeded ? ? true ;
2023-03-31 11:47:53 -04:00
}
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
internal void SyncWithParent ( )
{
if ( Parent . pCtrl is null ) return ;
Parent . pCtrl . RemoveAllRoots ( ) ;
foreach ( var kv in onlyShowChildren )
2020-08-06 19:16:40 -04:00
{
2023-03-31 11:47:53 -04:00
Parent . pCtrl . AppendRoot ( kv . Key . IShellItem , kv . Key . IsFolder ? SHCONTF . SHCONTF_FOLDERS : SHCONTF . SHCONTF_NONFOLDERS ,
kv . Value ? NSTCROOTSTYLE . NSTCRS_HIDDEN : NSTCROOTSTYLE . NSTCRS_VISIBLE ) ;
2020-08-06 19:16:40 -04:00
}
2023-03-31 11:47:53 -04:00
}
2020-08-06 19:16:40 -04:00
2023-03-31 11:47:53 -04:00
/// <summary>Adds an object to the end of the list.</summary>
/// <param name="item">The object to be added to the end of the list. The value can be <see langword="null"/> for reference types.</param>
void ICollection < ShellItem > . Add ( ShellItem item ) = > Add ( item , false , false ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Determines whether an element is in the list.</summary>
/// <param name="item">The object to locate in the list. The value can be <see langword="null"/> for reference types.</param>
/// <returns><see langword="true"/> if item is found in the list; otherwise, <see langword="false"/>.</returns>
bool ICollection < ShellItem > . Contains ( ShellItem item ) = > onlyShowChildren . ContainsKey ( item ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Returns an enumerator that iterates through the list.</summary>
/// <returns>An <see cref="IEnumerator"/> for the list.</returns>
IEnumerator IEnumerable . GetEnumerator ( ) = > GetEnumerator ( ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Inserts an element into the lsit at the specified index.</summary>
/// <param name="index">The zero-based index at which item should be inserted.</param>
/// <param name="item">The object to insert. The value can be null for reference types.</param>
void IList < ShellItem > . Insert ( int index , ShellItem item ) = > Insert ( index , item , false , false ) ;
2020-02-12 22:36:39 -05:00
2023-03-31 11:47:53 -04:00
/// <summary>Removes the element at the specified index of the list.</summary>
/// <param name="index">The zero-based index of the element to remove.</param>
2023-09-29 13:58:35 -04:00
void IList < ShellItem > . RemoveAt ( int index ) = > Remove ( this [ index ] ) ;
2023-03-31 11:47:53 -04:00
2023-09-29 13:58:35 -04:00
internal ShellItemArray GetItemArray ( ) = > Parent . pCtrl is not null & & Parent . pCtrl . GetRootItems ( out var pItems ) . Succeeded ? new ShellItemArray ( pItems ) : new ShellItemArray ( ) ;
2020-02-12 22:36:39 -05:00
}