2019-11-21 18:55:32 -05:00
// Heavily leverages the work done by Microsoft on the control by the same name in WindowsVistaApiPack. Work was done to improve the
// designer experience, remove nested properties, add missing capabilities, simplify COM calls, align names to those in other mainstream
// controls, and use the Vanara libraries.
2019-01-11 20:07:23 -05:00
using System.Collections ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Drawing ;
using System.Linq ;
using System.Windows.Forms ;
using System.Windows.Forms.VisualStyles ;
using Vanara.PInvoke ;
using Vanara.Windows.Shell ;
2020-12-14 18:12:11 -05:00
using static Vanara . PInvoke . Ole32 ;
2019-01-11 20:07:23 -05:00
using static Vanara . PInvoke . Shell32 ;
using static Vanara . PInvoke . ShlwApi ;
2019-08-27 18:03:21 -04:00
using static Vanara . PInvoke . User32 ;
2020-12-14 18:12:11 -05:00
using IMessageFilter = System . Windows . Forms . IMessageFilter ;
2019-01-11 20:07:23 -05:00
using IServiceProvider = Vanara . PInvoke . Shell32 . IServiceProvider ;
2023-03-31 11:47:53 -04:00
namespace Vanara.Windows.Forms ;
2023-09-24 17:26:46 -04:00
/// <summary>
/// Indicates the content options of the explorer browser. Typically use one, or a bitwise combination of these flags to specify how
/// content should appear in the explorer browser control
/// </summary>
[Flags]
2023-09-29 13:58:35 -04:00
public enum ExplorerBrowserContentSectionOptions : uint
{
/// <summary>No options.</summary>
None = FOLDERFLAGS . FWF_NONE ,
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>The view should be left-aligned.</summary>
AlignLeft = FOLDERFLAGS . FWF_ALIGNLEFT ,
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>Automatically arrange the elements in the view.</summary>
AutoArrange = FOLDERFLAGS . FWF_AUTOARRANGE ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Turns on check mode for the view</summary>
CheckSelect = FOLDERFLAGS . FWF_CHECKSELECT ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>When the view is set to "Tile" the layout of a single item should be extended to the width of the view.</summary>
ExtendedTiles = FOLDERFLAGS . FWF_EXTENDEDTILES ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>When an item is selected, the item and all its sub-items are highlighted.</summary>
FullRowSelect = FOLDERFLAGS . FWF_FULLROWSELECT ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>The view should not display file names</summary>
HideFileNames = FOLDERFLAGS . FWF_HIDEFILENAMES ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>The view should not save view state in the browser.</summary>
NoBrowserViewState = FOLDERFLAGS . FWF_NOBROWSERVIEWSTATE ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Do not display a column header in the view in any view mode.</summary>
NoColumnHeader = FOLDERFLAGS . FWF_NOCOLUMNHEADER ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Only show the column header in details view mode.</summary>
NoHeaderInAllViews = FOLDERFLAGS . FWF_NOHEADERINALLVIEWS ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>The view should not display icons.</summary>
NoIcons = FOLDERFLAGS . FWF_NOICONS ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Do not show subfolders.</summary>
NoSubfolders = FOLDERFLAGS . FWF_NOSUBFOLDERS ,
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>Navigate with a single click</summary>
SingleClickActivate = FOLDERFLAGS . FWF_SINGLECLICKACTIVATE ,
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>Do not allow more than a single item to be selected.</summary>
SingleSelection = FOLDERFLAGS . FWF_SINGLESEL ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>
/// Make the folder behave like the desktop. This value applies only to the desktop and is not used for typical Shell folders.
/// </summary>
Desktop = FOLDERFLAGS . FWF_DESKTOP ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Draw transparently. This is used only for the desktop.</summary>
Transparent = FOLDERFLAGS . FWF_TRANSPARENT ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Do not add scroll bars. This is used only for the desktop.</summary>
NoScrollBars = FOLDERFLAGS . FWF_NOSCROLL ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>The view should not be shown as a web view.</summary>
NoWebView = FOLDERFLAGS . FWF_NOWEBVIEW ,
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>
/// Windows Vista and later. Do not re-enumerate the view (or drop the current contents of the view) when the view is refreshed.
/// </summary>
NoEnumOnRefresh = FOLDERFLAGS . FWF_NOENUMREFRESH ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Windows Vista and later. Do not allow grouping in the view</summary>
NoGrouping = FOLDERFLAGS . FWF_NOGROUPING ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>Windows Vista and later. Do not display filters in the view.</summary>
NoFilters = FOLDERFLAGS . FWF_NOFILTERS ,
/// <summary>Windows Vista and later. Items can be selected using check-boxes.</summary>
AutoCheckSelect = FOLDERFLAGS . FWF_AUTOCHECKSELECT ,
/// <summary>Windows Vista and later. The view should list the number of items displayed in each group. To be used with IFolderView2::SetGroupSubsetCount.</summary>
SubsetGroup = FOLDERFLAGS . FWF_SUBSETGROUPS ,
/// <summary>Windows Vista and later. Use the search folder for stacking and searching.</summary>
UseSearchFolder = FOLDERFLAGS . FWF_USESEARCHFOLDER ,
/// <summary>
/// Windows Vista and later. Ensure right-to-left reading layout in a right-to-left system. Without this flag, the view displays
/// strings from left-to-right both on systems set to left-to-right and right-to-left reading layout, which ensures that file names
/// display correctly.
/// </summary>
AllowRtlReading = FOLDERFLAGS . FWF_ALLOWRTLREADING ,
}
/// <summary>These flags are used with <see cref="ExplorerBrowser.LoadCustomItems"/>.</summary>
[Flags]
public enum ExplorerBrowserLoadFlags
{
/// <summary>No flags.</summary>
None = EXPLORER_BROWSER_FILL_FLAGS . EBF_NONE ,
/// <summary>
/// Causes <see cref="ExplorerBrowser.LoadCustomItems"/> to first populate the results folder with the contents of the parent
/// folders of the items in the data object, and then select only the items that are in the data object.
/// </summary>
SelectFromDataObject = EXPLORER_BROWSER_FILL_FLAGS . EBF_SELECTFROMDATAOBJECT ,
2020-09-19 23:33:13 -04:00
2023-09-29 13:58:35 -04:00
/// <summary>
/// Do not allow dropping on the folder. In other words, do not register a drop target for the view. Applications can then register
/// their own drop targets.
/// </summary>
NoDropTarget = EXPLORER_BROWSER_FILL_FLAGS . EBF_NODROPTARGET ,
}
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>
/// Specifies the options that control subsequent navigation. Typically use one, or a bitwise combination of these flags to specify how
/// the explorer browser navigates.
/// </summary>
[Flags]
public enum ExplorerBrowserNavigateOptions
{
/// <summary>No options.</summary>
None = EXPLORER_BROWSER_OPTIONS . EBO_NONE ,
/// <summary>Always navigate, even if you are attempting to navigate to the current folder.</summary>
AlwaysNavigate = EXPLORER_BROWSER_OPTIONS . EBO_ALWAYSNAVIGATE ,
/// <summary>Do not navigate further than the initial navigation.</summary>
NavigateOnce = EXPLORER_BROWSER_OPTIONS . EBO_NAVIGATEONCE ,
/// <summary>
/// Use the following standard panes: Commands Module pane, Navigation pane, Details pane, and Preview pane. An implementer of
/// IExplorerPaneVisibility can modify the components of the Commands Module that are shown. For more information see,
/// IExplorerPaneVisibility::GetPaneState. If EBO_SHOWFRAMES is not set, Explorer browser uses a single view object.
/// </summary>
ShowFrames = EXPLORER_BROWSER_OPTIONS . EBO_SHOWFRAMES ,
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>Do not update the travel log.</summary>
NoTravelLog = EXPLORER_BROWSER_OPTIONS . EBO_NOTRAVELLOG ,
2019-01-11 20:07:23 -05:00
2023-09-29 13:58:35 -04:00
/// <summary>Do not use a wrapper window. This flag is used with legacy clients that need the browser parented directly on themselves.</summary>
NoWrapperWindow = EXPLORER_BROWSER_OPTIONS . EBO_NOWRAPPERWINDOW ,
/// <summary>Show WebView for SharePoint sites.</summary>
HtmlSharePointView = EXPLORER_BROWSER_OPTIONS . EBO_HTMLSHAREPOINTVIEW ,
/// <summary>Introduced in Windows Vista. Do not draw a border around the browser window.</summary>
NoBorder = EXPLORER_BROWSER_OPTIONS . EBO_NOBORDER ,
/// <summary>Introduced in Windows Vista. Do not persist the view state.</summary>
NoPersistViewState = EXPLORER_BROWSER_OPTIONS . EBO_NOPERSISTVIEWSTATE ,
}
/// <summary>Flags specifying the folder to be browsed.</summary>
[Flags]
public enum ExplorerBrowserNavigationItemCategory : uint
{
/// <summary>An absolute PIDL, relative to the desktop.</summary>
Absolute = SBSP . SBSP_ABSOLUTE ,
/// <summary>Windows Vista and later. Navigate without the default behavior of setting focus into the new view.</summary>
ActivateNoFocus = SBSP . SBSP_ACTIVATE_NOFOCUS ,
/// <summary>Enable auto-navigation.</summary>
AllowAutoNavigate = SBSP . SBSP_ALLOW_AUTONAVIGATE ,
/// <summary>
/// Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The navigation was possibly initiated by a web page with scripting
/// code already present on the local system.
/// </summary>
CallerUntrusted = SBSP . SBSP_CALLERUNTRUSTED ,
/// <summary>
/// Windows 7 and later. Do not add a new entry to the travel log. When the user enters a search term in the search box and
/// subsequently refines the query, the browser navigates forward but does not add an additional travel log entry.
/// </summary>
CreateNoHistory = SBSP . SBSP_CREATENOHISTORY ,
/// <summary>
/// Use default behavior, which respects the view option (the user setting to create new windows or to browse in place). In most
/// cases, calling applications should use this flag.
/// </summary>
Default = SBSP . SBSP_DEFBROWSER ,
/// <summary>Use the current window.</summary>
UseCurrentWindow = SBSP . SBSP_DEFMODE ,
/// <summary>
/// Specifies a folder tree for the new browse window. If the current browser does not match the SBSP.SBSP_EXPLOREMODE of the browse
/// object call, a new window is opened.
/// </summary>
ExploreMode = SBSP . SBSP_EXPLOREMODE ,
/// <summary>
/// Windows Internet Explorer 7 and later. If allowed by current registry settings, give the browser a destination to navigate to.
/// </summary>
FeedNavigation = SBSP . SBSP_FEEDNAVIGATION ,
/// <summary>Windows Vista and later. Navigate without clearing the search entry field.</summary>
KeepSearchText = SBSP . SBSP_KEEPWORDWHEELTEXT ,
/// <summary>Navigate back, ignore the PIDL.</summary>
NavigateBack = SBSP . SBSP_NAVIGATEBACK ,
/// <summary>Navigate forward, ignore the PIDL.</summary>
NavigateForward = SBSP . SBSP_NAVIGATEFORWARD ,
/// <summary>Creates another window for the specified folder.</summary>
NewWindow = SBSP . SBSP_NEWBROWSER ,
/// <summary>Suppress selection in the history pane.</summary>
NoHistorySelect = SBSP . SBSP_NOAUTOSELECT ,
/// <summary>Do not transfer the browsing history to the new window.</summary>
NoTransferHistory = SBSP . SBSP_NOTRANSFERHIST ,
/// <summary>
/// Specifies no folder tree for the new browse window. If the current browser does not match the SBSP.SBSP_OPENMODE of the browse
/// object call, a new window is opened.
/// </summary>
NoFolderTree = SBSP . SBSP_OPENMODE ,
/// <summary>Browse the parent folder, ignore the PIDL.</summary>
ParentFolder = SBSP . SBSP_PARENT ,
/// <summary>Windows 7 and later. Do not make the navigation complete sound for each keystroke in the search box.</summary>
PlayNoSound = SBSP . SBSP_PLAYNOSOUND ,
/// <summary>Enables redirection to another URL.</summary>
Redirect = SBSP . SBSP_REDIRECT ,
/// <summary>A relative PIDL, relative to the current folder.</summary>
Relative = SBSP . SBSP_RELATIVE ,
/// <summary>Browse to another folder with the same Windows Explorer window.</summary>
SameWindow = SBSP . SBSP_SAMEBROWSER ,
/// <summary>Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The navigate should allow ActiveX prompts.</summary>
TrustedForActiveX = SBSP . SBSP_TRUSTEDFORACTIVEX ,
/// <summary>
/// Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The new window is the result of a user initiated action. Trust the
/// new window if it immediately attempts to download content.
/// </summary>
TrustFirstDownload = SBSP . SBSP_TRUSTFIRSTDOWNLOAD ,
/// <summary>
/// Microsoft Internet Explorer 6 Service Pack 2 (SP2) and later. The window is navigating to an untrusted, non-HTML file. If the
/// user attempts to download the file, do not allow the download.
/// </summary>
UntrustedForDownload = SBSP . SBSP_UNTRUSTEDFORDOWNLOAD ,
/// <summary>Write no history of this navigation in the history Shell folder.</summary>
WriteNoHistory = SBSP . SBSP_WRITENOHISTORY
}
/// <summary>Indicates the viewing mode of the explorer browser</summary>
public enum ExplorerBrowserViewMode
{
/// <summary>Choose the best view mode for the folder</summary>
Auto = FOLDERVIEWMODE . FVM_AUTO ,
/// <summary>(New for Windows7)</summary>
Content = FOLDERVIEWMODE . FVM_CONTENT ,
/// <summary>Object names and other selected information, such as the size or date last updated, are shown.</summary>
Details = FOLDERVIEWMODE . FVM_DETAILS ,
/// <summary>The view should display medium-size icons.</summary>
Icon = FOLDERVIEWMODE . FVM_ICON ,
/// <summary>Object names are displayed in a list view.</summary>
List = FOLDERVIEWMODE . FVM_LIST ,
/// <summary>The view should display small icons.</summary>
SmallIcon = FOLDERVIEWMODE . FVM_SMALLICON ,
/// <summary>The view should display thumbnail icons.</summary>
Thumbnail = FOLDERVIEWMODE . FVM_THUMBNAIL ,
/// <summary>The view should display icons in a filmstrip format.</summary>
ThumbStrip = FOLDERVIEWMODE . FVM_THUMBSTRIP ,
/// <summary>The view should display large icons.</summary>
Tile = FOLDERVIEWMODE . FVM_TILE
}
/// <summary>Indicates the visibility state of an ExplorerBrowser pane.</summary>
public enum PaneVisibilityState
{
/// <summary>Allow the explorer browser to determine if this pane is displayed.</summary>
Default = EXPLORERPANESTATE . EPS_DONTCARE ,
/// <summary>Hide the pane</summary>
Hide = EXPLORERPANESTATE . EPS_DEFAULT_OFF | EXPLORERPANESTATE . EPS_FORCE ,
/// <summary>Show the pane</summary>
Show = EXPLORERPANESTATE . EPS_DEFAULT_ON | EXPLORERPANESTATE . EPS_FORCE
}
/// <summary>
/// <c>ExplorerBrowser</c> is a browser object that can be either navigated or that can host a view of a data object. As a full-featured
/// browser object, it also supports an automatic travel log.
/// </summary>
/// <seealso cref="Control"/>
/// <seealso cref="IServiceProvider"/>
/// <seealso cref="IExplorerPaneVisibility"/>
/// <seealso cref="IExplorerBrowserEvents"/>
/// <seealso cref="ICommDlgBrowser3"/>
/// <seealso cref="IMessageFilter"/>
[Designer(typeof(Design.ExplorerBrowserDesigner)), DefaultProperty(nameof(Name)), DefaultEvent(nameof(SelectionChanged))]
[ToolboxItem(true), ToolboxBitmap(typeof(ExplorerBrowser), "ExplorerBrowser.bmp")]
[Description("A Shell browser object that can be either navigated or that can host a view of a data object.")]
[ComVisible(true), Guid("01103386-B66B-4AFB-AF50-78AED6E562DA")]
public class ExplorerBrowser : Control , ICommDlgBrowser3 , IExplorerBrowserEvents , IExplorerPaneVisibility , IMessageFilter , IServiceProvider
{
internal uint eventsCookie ;
internal IExplorerBrowser ? explorerBrowserControl ;
internal FOLDERSETTINGS folderSettings = new ( FOLDERVIEWMODE . FVM_AUTO , defaultFolderFlags ) ;
private const FOLDERFLAGS defaultFolderFlags = FOLDERFLAGS . FWF_USESEARCHFOLDER | FOLDERFLAGS . FWF_NOWEBVIEW ;
private const int defaultThumbnailSize = 32 ;
private const int HRESULT_CANCELLED = unchecked ( ( int ) 0x800704C7 ) ;
private const int HRESULT_RESOURCE_IN_USE = unchecked ( ( int ) 0x800700AA ) ;
private static readonly string defaultPropBagName = typeof ( ExplorerBrowser ) . FullName ! ;
private static readonly Guid IID_ICommDlgBrowser = typeof ( ICommDlgBrowser ) . GUID ;
private readonly IContainer ? components = null ;
private ( ShellItem ? item , ExplorerBrowserNavigationItemCategory category ) antecreationNavigationTarget ;
private EXPLORER_BROWSER_OPTIONS options = EXPLORER_BROWSER_OPTIONS . EBO_SHOWFRAMES ;
private string propertyBagName = defaultPropBagName ;
private int thumbnailSize = defaultThumbnailSize ;
private ViewEvents ? viewEvents ;
/// <summary>Initializes a new instance of the <see cref="ExplorerBrowser"/> class.</summary>
public ExplorerBrowser ( )
{
components = new Container ( ) ;
//AutoScaleMode = AutoScaleMode.Font;
History = new NavigationLog ( this ) ;
Items = new ShellItemCollection ( this , SVGIO . SVGIO_ALLVIEW ) ;
SelectedItems = new ShellItemCollection ( this , SVGIO . SVGIO_SELECTION ) ;
}
/// <summary>Fires when the Items collection changes.</summary>
[Category("Action"), Description("Items changed.")]
public event EventHandler ? ItemsChanged ;
/// <summary>Fires when the ExplorerBorwser view has finished enumerating files.</summary>
[Category("Behavior"), Description("View is done enumerating files.")]
public event EventHandler ? ItemsEnumerated ;
/// <summary>
/// Fires when a navigation has been 'completed': no Navigating listener has canceled, and the ExplorerBorwser has created a new
/// view. The view will be populated with new items asynchronously, and ItemsChanged will be fired to reflect this some time later.
/// </summary>
[Category("Action"), Description("Navigation complete.")]
public event EventHandler < NavigatedEventArgs > ? Navigated ;
/// <summary>Fires when a navigation has been initiated, but is not yet complete.</summary>
[Category("Action"), Description("Navigation initiated, but not complete.")]
public event EventHandler < NavigatingEventArgs > ? Navigating ;
/// <summary>
/// Fires when either a Navigating listener cancels the navigation, or if the operating system determines that navigation is not possible.
/// </summary>
[Category("Action"), Description("Navigation failed.")]
public event EventHandler < NavigationFailedEventArgs > ? NavigationFailed ;
/// <summary>Fires when the item selected in the view has changed (i.e., a rename ). This is not the same as SelectionChanged.</summary>
[Category("Action"), Description("Selected item has changed.")]
public event EventHandler ? SelectedItemModified ;
/// <summary>Fires when the SelectedItems collection changes.</summary>
[Category("Behavior"), Description("Selection changed.")]
public event EventHandler ? SelectionChanged ;
// *** The implementation in Shell32 uses MSG which has proven to be slow. This passes the Message structure directly. ***
[ComImport, Guid("68284fAA-6A48-11D0-8c78-00C04fd918b4"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IInputObject_WinForms
{
[PreserveSig]
HRESULT UIActivateIO ( [ In , MarshalAs ( UnmanagedType . Bool ) ] bool fActivate , in Message pMsg ) ;
[PreserveSig]
HRESULT HasFocusIO ( ) ;
[PreserveSig]
HRESULT TranslateAcceleratorIO ( in Message pMsg ) ;
}
/// <summary>The view should be left-aligned.</summary>
[Browsable(false), DefaultValue(false), Category("Appearance"), Description("The view should be left-aligned.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool AlignLeft
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . AlignLeft ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . AlignLeft , value ) ;
}
/// <summary>
/// Ensure right-to-left reading layout in a right-to-left system. Without this flag, the view displays strings from left-to-right
/// both on systems set to left-to-right and right-to-left reading layout, which ensures that file names display correctly.
/// </summary>
[Browsable(false), DefaultValue(false), Category("Appearance"), Description("Ensure right-to-left reading layout in a right-to-left system.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool AllowRtlReading
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . AllowRtlReading ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . AllowRtlReading , value ) ;
}
/// <summary>Always navigate, even if you are attempting to navigate to the current folder.</summary>
[DefaultValue(false), Category("Behavior"), Description("Always navigate, even if you are attempting to navigate to the current folder.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool AlwaysNavigate
{
get = > IsNavFlagSet ( ExplorerBrowserNavigateOptions . AlwaysNavigate ) ;
set = > SetNavFlag ( ExplorerBrowserNavigateOptions . AlwaysNavigate , value ) ;
}
/// <summary>Automatically arrange the elements in the view.</summary>
[DefaultValue(false), Category("Behavior"), Description("Automatically arrange the elements in the view.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool AutoArrange
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . AutoArrange ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . AutoArrange , value ) ;
}
/// <summary>Items can be selected using check-boxes.</summary>
[DefaultValue(false), Category("Behavior"), Description("Items can be selected using check-boxes.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool AutoCheckSelect
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . AutoCheckSelect ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . AutoCheckSelect , value ) ;
}
/// <summary>Turns on check mode for the view</summary>
[DefaultValue(false), Category("Behavior"), Description("Turns on check mode for the view")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool CheckSelect
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . CheckSelect ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . CheckSelect , value ) ;
}
/// <summary>The binary representation of the ExplorerBrowser content flags</summary>
[Browsable(false), DefaultValue(0), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public ExplorerBrowserContentSectionOptions ContentFlags
{
get = > ( ExplorerBrowserContentSectionOptions ) folderSettings . fFlags ;
set
{
folderSettings . fFlags = ( FOLDERFLAGS ) value | defaultFolderFlags ;
explorerBrowserControl ? . SetFolderSettings ( folderSettings ) ;
}
}
/// <summary>Make the folder behave like the desktop. This applies only to the desktop and is not used for typical Shell folders.</summary>
[Browsable(false), DefaultValue(false), Category("Appearance"), Description("Make the folder behave like the desktop.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool Desktop
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . Desktop ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . Desktop , value ) ;
}
/// <summary>When the view is in "tile view mode" the layout of a single item should be extended to the width of the view.</summary>
[DefaultValue(false), Category("Appearance"), Description("The layout of a single item should be extended to the width of the view.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool ExtendedTiles
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . ExtendedTiles ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . ExtendedTiles , value ) ;
}
/// <summary>When an item is selected, the item and all its sub-items are highlighted.</summary>
[DefaultValue(false), Category("Behavior"), Description("When an item is selected, the item and all its sub-items are highlighted.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool FullRowSelect
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . FullRowSelect ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . FullRowSelect , value ) ;
}
/// <summary>The view should not display file names</summary>
[DefaultValue(false), Category("Appearance"), Description("The view should not display file names")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool HideFileNames
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . HideFileNames ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . HideFileNames , value ) ;
}
/// <summary>Contains the navigation history of the ExplorerBrowser</summary>
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public NavigationLog History { get ; }
/// <summary>The set of ShellItems in the Explorer Browser</summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IReadOnlyList < ShellItem > Items { get ; }
/// <summary>Do not navigate further than the initial navigation.</summary>
[DefaultValue(false), Category("Behavior"), Description("Do not navigate further than the initial navigation.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NavigateOnce
{
get = > IsNavFlagSet ( ExplorerBrowserNavigateOptions . NavigateOnce ) ;
set = > SetNavFlag ( ExplorerBrowserNavigateOptions . NavigateOnce , value ) ;
}
/// <summary>The binary flags that are passed to the explorer browser control's GetOptions/SetOptions methods</summary>
[Browsable(false), DefaultValue(0), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public ExplorerBrowserNavigateOptions NavigationFlags
{
get
{
explorerBrowserControl ? . GetOptions ( out options ) ;
return ( ExplorerBrowserNavigateOptions ) options ;
}
// Always forcing SHOWFRAMES because we handle IExplorerPaneVisibility
set = > explorerBrowserControl ? . SetOptions ( options = ( EXPLORER_BROWSER_OPTIONS ) value | EXPLORER_BROWSER_OPTIONS . EBO_SHOWFRAMES ) ;
}
/// <summary>The view should not save view state in the browser.</summary>
[DefaultValue(false), Category("Behavior"), Description("The view should not save view state in the browser.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoBrowserViewState
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoBrowserViewState ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoBrowserViewState , value ) ;
}
/// <summary>Do not display a column header in the view in any view mode.</summary>
[DefaultValue(false), Category("Appearance"), Description("Do not display a column header in the view in any view mode.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoColumnHeader
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoColumnHeader ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoColumnHeader , value ) ;
}
/// <summary>Do not re-enumerate the view (or drop the current contents of the view) when the view is refreshed.</summary>
[DefaultValue(false), Category("Behavior"), Description("Do not re-enumerate the view (or drop the current contents of the view) when the view is refreshed.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoEnumOnRefresh
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoEnumOnRefresh ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoEnumOnRefresh , value ) ;
}
/// <summary>Do not display filters in the view.</summary>
[DefaultValue(false), Category("Appearance"), Description("Do not display filters in the view.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoFilters
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoFilters ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoFilters , value ) ;
}
/// <summary>Do not allow grouping in the view.</summary>
[DefaultValue(false), Category("Appearance"), Description("Do not allow grouping in the view.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoGrouping
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoGrouping ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoGrouping , value ) ;
}
/// <summary>Only show the column header in details view mode.</summary>
[DefaultValue(false), Category("Appearance"), Description("Only show the column header in details view mode.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoHeaderInAllViews
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoHeaderInAllViews ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoHeaderInAllViews , value ) ;
}
/// <summary>The view should not display icons.</summary>
[DefaultValue(false), Category("Appearance"), Description("The view should not display icons.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoIcons
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoIcons ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoIcons , value ) ;
}
/// <summary>Introduced in Windows Vista. Do not persist the view state.</summary>
[DefaultValue(false), Category("Behavior"), Description("Do not persist the view state.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoPersistViewState
{
get = > IsNavFlagSet ( ExplorerBrowserNavigateOptions . NoPersistViewState ) ;
set = > SetNavFlag ( ExplorerBrowserNavigateOptions . NoPersistViewState , value ) ;
}
/// <summary>Do not add scroll bars. This is used only for the desktop.</summary>
[Browsable(false), DefaultValue(false), Category("Appearance"), Description("Do not add scroll bars.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoScrollBars
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoScrollBars ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoScrollBars , value ) ;
}
/// <summary>Do not show subfolders.</summary>
[DefaultValue(false), Category("Appearance"), Description("Do not show subfolders.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoSubfolders
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . NoSubfolders ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . NoSubfolders , value ) ;
}
/// <summary>Do not update the travel log.</summary>
[DefaultValue(false), Category("Behavior"), Description("Do not update the travel log.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoTravelLog
{
get = > IsNavFlagSet ( ExplorerBrowserNavigateOptions . NoTravelLog ) ;
set = > SetNavFlag ( ExplorerBrowserNavigateOptions . NoTravelLog , value ) ;
}
/// <summary>Do not use a wrapper window. This flag is used with legacy clients that need the browser parented directly on themselves.</summary>
[Browsable(false), DefaultValue(false), Category("Behavior"), Description("Do not use a wrapper window.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool NoWrapperWindow
{
get = > IsNavFlagSet ( ExplorerBrowserNavigateOptions . NoWrapperWindow ) ;
set = > SetNavFlag ( ExplorerBrowserNavigateOptions . NoWrapperWindow , value ) ;
}
/// <summary>Controls the visibility of the various ExplorerBrowser panes on subsequent navigation</summary>
[Category("Appearance"), Description("Set visibility of child panes.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ExplorerBrowserPaneVisibility PaneVisibility { get ; } = new ExplorerBrowserPaneVisibility ( ) ;
/// <summary>The name of the property bag used to persist changes to the ExplorerBrowser's view state.</summary>
[Browsable(false), Category("Data"), Description("Name of the property bag used to persist changes to the ExplorerBrowser's view state")]
public string PropertyBagName
{
get = > propertyBagName ;
set { propertyBagName = value ; explorerBrowserControl ? . SetPropertyBag ( propertyBagName ) ; }
}
/// <summary>The set of selected ShellItems in the Explorer Browser</summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IReadOnlyList < ShellItem > SelectedItems { get ; }
/// <summary>Navigate with a single click.</summary>
[DefaultValue(false), Category("Behavior"), Description("Navigate with a single click.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool SingleClickActivate
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . SingleClickActivate ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . SingleClickActivate , value ) ;
}
/// <summary>Do not allow more than a single item to be selected.</summary>
[DefaultValue(false), Category("Behavior"), Description("Do not allow more than a single item to be selected.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool SingleSelection
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . SingleSelection ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . SingleSelection , value ) ;
}
/// <summary>The view should list the number of items displayed in each group.</summary>
[DefaultValue(false), Category("Appearance"), Description("The view should list the number of items displayed in each group.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool SubsetGroup
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . SubsetGroup ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . SubsetGroup , value ) ;
}
/// <summary>The size of the thumbnails in pixels.</summary>
[Category("Appearance"), DefaultValue(defaultThumbnailSize), Description("The size of the thumbnails in pixels.")]
public int ThumbnailSize
{
get
{
var fv2 = GetFolderView2 ( ) ;
fv2 ? . GetViewModeAndIconSize ( out _ , out thumbnailSize ) ;
return thumbnailSize ;
}
set
{
var fv2 = GetFolderView2 ( ) ;
if ( fv2 is null ) return ;
fv2 . GetViewModeAndIconSize ( out var fvm , out _ ) ;
fv2 . SetViewModeAndIconSize ( fvm , thumbnailSize = value ) ;
}
}
/// <summary>Draw transparently. This is used only for the desktop.</summary>
[Browsable(false), DefaultValue(false), Category("Appearance"), Description("Draw transparently.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool Transparent
{
get = > IsContentFlagSet ( ExplorerBrowserContentSectionOptions . Transparent ) ;
set = > SetContentFlag ( ExplorerBrowserContentSectionOptions . Transparent , value ) ;
}
/// <summary>Show WebView for SharePoint sites.</summary>
[Browsable(false), DefaultValue(false), Category("Behavior"), Description("Show WebView for SharePoint sites.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public bool UseHtmlSharePointView
{
get = > IsNavFlagSet ( ExplorerBrowserNavigateOptions . HtmlSharePointView ) ;
set = > SetNavFlag ( ExplorerBrowserNavigateOptions . HtmlSharePointView , value ) ;
}
/// <summary>The viewing mode of the Explorer Browser</summary>
[DefaultValue(typeof(ExplorerBrowserViewMode), "Auto"), Category("Appearance"), Description("The viewing mode of the Explorer Browser.")]
public ExplorerBrowserViewMode ViewMode
{
get = > ( ExplorerBrowserViewMode ) folderSettings . ViewMode ;
set
{
folderSettings . ViewMode = ( FOLDERVIEWMODE ) value ;
explorerBrowserControl ? . SetFolderSettings ( folderSettings ) ;
}
}
/// <inheritdoc/>
protected override Size DefaultSize = > new ( 200 , 150 ) ;
/// <summary>Removes all items from the results folder.</summary>
public void ClearCustomItems ( ) = > explorerBrowserControl ? . RemoveAll ( ) ;
/// <summary>
/// Exposes the underlying interfaces for the control. Using this interface directly to call methods will result in unexpected
/// results with the control and can cause instability.
/// </summary>
/// <returns>The <see cref="IExplorerBrowser"/> instance used by this control.</returns>
public IExplorerBrowser ? DangerousGetInterface ( ) = > explorerBrowserControl ;
/// <summary>Creates a custom folder and fills it with items.</summary>
/// <param name="obj">
/// An interface pointer on the source object that will fill the control. This can be an <see cref="IDataObject"/> or any object
/// that can be used with <see cref="INamespaceWalk"/>.
/// </param>
/// <param name="flags">One of the <see cref="ExplorerBrowserLoadFlags"/> values.</param>
public void LoadCustomItems ( object obj , ExplorerBrowserLoadFlags flags = ExplorerBrowserLoadFlags . None ) = > explorerBrowserControl ? . FillFromObject ( obj , ( EXPLORER_BROWSER_FILL_FLAGS ) flags ) ;
/// <summary>
/// Clears the Explorer Browser of existing content, fills it with content from the specified container, and adds a new point to the
/// Travel Log.
/// </summary>
/// <param name="shellItem">The shell container to navigate to.</param>
/// <param name="category">The category of the <paramref name="shellItem"/>.</param>
public void Navigate ( ShellItem ? shellItem , ExplorerBrowserNavigationItemCategory category = ExplorerBrowserNavigationItemCategory . Default )
{
if ( explorerBrowserControl is null )
{
antecreationNavigationTarget = ( shellItem , category ) ;
}
else if ( shellItem is not null )
{
var hr = explorerBrowserControl . BrowseToObject ( shellItem . IShellItem , ( SBSP ) category ) ;
if ( hr = = HRESULT_RESOURCE_IN_USE | | hr = = HRESULT_CANCELLED )
OnNavigationFailed ( new NavigationFailedEventArgs { FailedLocation = shellItem } ) ;
else if ( hr . Failed )
throw new ArgumentException ( "Unable to browse to this shell item." , nameof ( shellItem ) , hr . GetException ( ) ) ;
}
}
/// <summary>
/// Navigates to the last item in the navigation history list. This does not change the set of locations in the navigation log.
/// </summary>
public bool NavigateBack ( ) { if ( History . CanNavigateBackward ) { Navigate ( null , ExplorerBrowserNavigationItemCategory . NavigateBack ) ; return true ; } return false ; }
/// <summary>
/// Navigates to the next item in the navigation history list. This does not change the set of locations in the navigation log.
/// </summary>
/// <returns>True if the navigation succeeded, false if it failed for any reason.</returns>
public bool NavigateForward ( ) { if ( History . CanNavigateForward ) { Navigate ( null , ExplorerBrowserNavigationItemCategory . NavigateForward ) ; return true ; } return false ; }
/// <summary>
/// Navigate within the navigation log in a specific direciton. This does not change the set of locations in the navigation log.
/// </summary>
/// <param name="direction">The direction to navigate within the navigation logs collection.</param>
/// <returns>True if the navigation succeeded, false if it failed for any reason.</returns>
public bool NavigateFromHistory ( NavigationLogDirection direction ) = > History . NavigateLog ( direction ) ;
/// <summary>Navigate within the navigation log. This does not change the set of locations in the navigation log.</summary>
/// <param name="historyIndex">An index into the navigation logs Locations collection.</param>
/// <returns>True if the navigation succeeded, false if it failed for any reason.</returns>
public bool NavigateToHistoryIndex ( int historyIndex ) = > History . NavigateLog ( historyIndex ) ;
/// <summary>Selects all items in the current view.</summary>
public void SelectAll ( )
{
var fv2 = GetFolderView2 ( ) ;
if ( fv2 is null ) return ;
for ( var i = 0 ; i < fv2 . ItemCount ( SVGIO . SVGIO_ALLVIEW ) ; i + + )
fv2 . SelectItem ( i , SVSIF . SVSI_SELECT ) ;
}
/// <summary>Unselects all items in the current view.</summary>
public void UnselectAll ( )
{
var fv2 = GetFolderView2 ( ) ;
fv2 ? . SelectItem ( - 1 , SVSIF . SVSI_DESELECTOTHERS ) ;
}
HRESULT ICommDlgBrowser3 . GetCurrentFilter ( StringBuilder pszFileSpec , int cchFileSpec ) = > HRESULT . S_OK ;
HRESULT ICommDlgBrowser3 . GetDefaultMenuText ( IShellView ppshv , StringBuilder pszText , int cchMax ) = > HRESULT . S_FALSE ;
HRESULT IExplorerPaneVisibility . GetPaneState ( in Guid ep , out EXPLORERPANESTATE peps )
{
peps = ep switch
{
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_AdvQueryPane ) = > ( EXPLORERPANESTATE ) PaneVisibility . AdvancedQuery ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_Commands ) = > ( EXPLORERPANESTATE ) PaneVisibility . Commands ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_Commands_Organize ) = > ( EXPLORERPANESTATE ) PaneVisibility . CommandsOrganize ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_Commands_View ) = > ( EXPLORERPANESTATE ) PaneVisibility . CommandsView ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_DetailsPane ) = > ( EXPLORERPANESTATE ) PaneVisibility . Details ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_NavPane ) = > ( EXPLORERPANESTATE ) PaneVisibility . Navigation ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_PreviewPane ) = > ( EXPLORERPANESTATE ) PaneVisibility . Preview ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_QueryPane ) = > ( EXPLORERPANESTATE ) PaneVisibility . Query ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_Ribbon ) = > ( EXPLORERPANESTATE ) PaneVisibility . Ribbon ,
var a when a . Equals ( IExplorerPaneVisibilityConstants . EP_StatusBar ) = > ( EXPLORERPANESTATE ) PaneVisibility . StatusBar ,
_ = > EXPLORERPANESTATE . EPS_DONTCARE ,
} ;
return HRESULT . S_OK ;
}
HRESULT ICommDlgBrowser3 . GetViewFlags ( out CDB2GVF pdwFlags )
{
pdwFlags = CDB2GVF . CDB2GVF_SHOWALLFILES ;
return HRESULT . S_OK ;
}
HRESULT ICommDlgBrowser3 . IncludeObject ( IShellView ppshv , IntPtr pidl )
{
OnItemsChanged ( ) ;
return HRESULT . S_OK ;
}
HRESULT ICommDlgBrowser3 . Notify ( IShellView ppshv , CDB2N dwNotifyType ) = > HRESULT . S_OK ;
HRESULT ICommDlgBrowser3 . OnColumnClicked ( IShellView ppshv , int iColumn ) = > HRESULT . S_OK ;
HRESULT ICommDlgBrowser3 . OnDefaultCommand ( IShellView ppshv ) = > HRESULT . S_FALSE ;
HRESULT IExplorerBrowserEvents . OnNavigationComplete ( IntPtr pidlFolder )
{
folderSettings . ViewMode = GetCurrentViewMode ( ) ;
OnNavigated ( new NavigatedEventArgs { NewLocation = new ShellItem ( new PIDL ( pidlFolder , clone : true ) ) } ) ;
// Remember! We're not the owner of the given PIDL, so we have to make our own copy for our own heap! See Issue #158
return HRESULT . S_OK ;
}
HRESULT IExplorerBrowserEvents . OnNavigationFailed ( IntPtr pidlFolder )
{
OnNavigationFailed ( new NavigationFailedEventArgs { FailedLocation = new ShellItem ( new PIDL ( pidlFolder , clone : true ) ) } ) ;
// Remember! We're not the owner of the given PIDL, so we have to make our own copy for our own heap! See Issue #158
return HRESULT . S_OK ;
}
HRESULT IExplorerBrowserEvents . OnNavigationPending ( IntPtr pidlFolder )
{
OnNavigating ( new NavigatingEventArgs { PendingLocation = new ShellItem ( new PIDL ( pidlFolder , clone : true ) ) } , out var cancelled ) ;
// Remember! We're not the owner of the given PIDL, so we have to make our own copy for our own heap! See Issue #158
return cancelled ? ( HRESULT ) HRESULT_CANCELLED : HRESULT . S_OK ;
}
HRESULT ICommDlgBrowser3 . OnPreViewCreated ( IShellView ppshv ) = > HRESULT . S_OK ;
HRESULT ICommDlgBrowser3 . OnStateChange ( IShellView ppshv , CDBOSC uChange )
{
if ( uChange = = CDBOSC . CDBOSC_SELCHANGE )
OnSelectionChanged ( ) ;
return HRESULT . S_OK ;
}
HRESULT IExplorerBrowserEvents . OnViewCreated ( IShellView psv )
{
viewEvents ? . ConnectToView ( psv ) ;
return HRESULT . S_OK ;
}
bool IMessageFilter . PreFilterMessage ( ref Message m )
{
if ( explorerBrowserControl is null ) return false ;
return ( ( IInputObject_WinForms ) explorerBrowserControl ) . TranslateAcceleratorIO ( m ) = = HRESULT . S_OK ;
}
HRESULT IServiceProvider . QueryService ( in Guid guidService , in Guid riid , out IntPtr ppvObject )
{
if ( guidService . Equals ( typeof ( IExplorerPaneVisibility ) . GUID ) )
{
ppvObject = Marshal . GetComInterfaceForObject ( this , typeof ( IExplorerPaneVisibility ) ) ;
return HRESULT . S_OK ;
}
else if ( guidService . Equals ( IID_ICommDlgBrowser ) & & ( riid . Equals ( IID_ICommDlgBrowser ) | | riid . Equals ( typeof ( ICommDlgBrowser3 ) . GUID ) ) )
{
ppvObject = Marshal . GetComInterfaceForObject ( this , typeof ( ICommDlgBrowser3 ) ) ;
return HRESULT . S_OK ;
}
ppvObject = default ;
return HRESULT . E_NOINTERFACE ;
}
/// <summary>Gets the IFolderView2 interface from the explorer browser.</summary>
/// <returns>An <see cref="IFolderView2"/> instance.</returns>
internal IFolderView2 ? GetFolderView2 ( ) { try { return explorerBrowserControl ? . GetCurrentView < IFolderView2 > ( ) ; } catch { return null ; } }
/// <summary>Gets the items in the ExplorerBrowser as an IShellItemArray</summary>
/// <returns>An <see cref="IShellItemArray"/> instance or <see langword="null"/> if not available.</returns>
internal IShellItemArray ? GetItemsArray ( SVGIO opt )
{
try
{
var fv2 = GetFolderView2 ( ) ;
return fv2 ? . Items < IShellItemArray > ( opt ) ;
}
catch { return null ; }
}
/// <summary>Raises the <see cref="ItemsChanged"/> event.</summary>
protected internal virtual void OnItemsChanged ( ) = > ItemsChanged ? . Invoke ( this , EventArgs . Empty ) ;
/// <summary>Raises the <see cref="ItemsEnumerated"/> event.</summary>
protected internal virtual void OnItemsEnumerated ( ) = > ItemsEnumerated ? . Invoke ( this , EventArgs . Empty ) ;
/// <summary>Raises the <see cref="Navigated"/> event.</summary>
protected internal virtual void OnNavigated ( NavigatedEventArgs ncevent )
{
if ( ncevent ? . NewLocation is null ) return ;
Navigated ? . Invoke ( this , ncevent ) ;
}
/// <summary>Raises the <see cref="Navigating"/> event.</summary>
protected internal virtual void OnNavigating ( NavigatingEventArgs npevent , out bool cancelled )
{
cancelled = false ;
if ( Navigating is null | | npevent ? . PendingLocation is null ) return ;
foreach ( var del in Navigating . GetInvocationList ( ) )
{
del . DynamicInvoke ( new object [ ] { this , npevent } ) ;
if ( npevent . Cancel )
cancelled = true ;
}
}
/// <summary>Raises the <see cref="NavigationFailed"/> event.</summary>
protected internal virtual void OnNavigationFailed ( NavigationFailedEventArgs nfevent )
{
if ( nfevent ? . FailedLocation is null ) return ;
NavigationFailed ? . Invoke ( this , nfevent ) ;
}
/// <summary>Raises the <see cref="SelectedItemModified"/> event.</summary>
protected internal virtual void OnSelectedItemModified ( ) = > SelectedItemModified ? . Invoke ( this , EventArgs . Empty ) ;
/// <summary>Raises the <see cref="SelectionChanged"/> event.</summary>
protected internal virtual void OnSelectionChanged ( ) = > SelectionChanged ? . Invoke ( this , EventArgs . Empty ) ;
/// <summary>Clean up any resources being used.</summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
components ? . Dispose ( ) ;
viewEvents ? . Dispose ( ) ;
}
base . Dispose ( disposing ) ;
}
/// <summary>Raises the <see cref="Control.CreateControl"/> method.</summary>
protected override void OnCreateControl ( )
{
base . OnCreateControl ( ) ;
if ( ! DesignMode )
{
explorerBrowserControl = new IExplorerBrowser ( ) ;
// hooks up IExplorerPaneVisibility and ICommDlgBrowser event notifications
SetSite ( this ) ;
// hooks up IExplorerBrowserEvents event notification
explorerBrowserControl . Advise ( this , out eventsCookie ) ;
// sets up ExplorerBrowser view connection point events
viewEvents = new ViewEvents ( this ) ;
explorerBrowserControl . Initialize ( Handle , ClientRectangle , folderSettings ) ;
// Force an initial show frames so that IExplorerPaneVisibility works the first time it is set. This also enables the
// control panel to be browsed to. If it is not set, then navigating to the control panel succeeds, but no items are visible
// in the view.
explorerBrowserControl . SetOptions ( options ) ;
explorerBrowserControl . SetPropertyBag ( propertyBagName ) ;
// ExplorerBrowserOptions.NoBorder does not work, so we do it manually...
RemoveWindowBorder ( ) ;
if ( antecreationNavigationTarget . item ! = null )
{
BeginInvoke ( new MethodInvoker ( delegate
{
Navigate ( antecreationNavigationTarget . item , antecreationNavigationTarget . category ) ;
antecreationNavigationTarget = default ;
} ) ) ;
}
}
Application . AddMessageFilter ( this ) ;
}
/// <summary>Cleans up the explorer browser events+object when the window is being taken down.</summary>
/// <param name="e">An EventArgs that contains event data.</param>
protected override void OnHandleDestroyed ( EventArgs e )
{
if ( explorerBrowserControl ! = null )
{
// unhook events
viewEvents ? . DisconnectFromView ( ) ;
explorerBrowserControl . Unadvise ( eventsCookie ) ;
SetSite ( null ) ;
// destroy the explorer browser control
explorerBrowserControl . Destroy ( ) ;
// release com reference to it
explorerBrowserControl = null ;
}
base . OnHandleDestroyed ( e ) ;
}
/// <summary>Raises the <see cref="E:Paint"/> event.</summary>
/// <param name="pe">The <see cref="PaintEventArgs"/> instance containing the event data.</param>
protected override void OnPaint ( PaintEventArgs pe )
{
if ( DesignMode & & pe ! = null )
{
var cr = ClientRectangle ;
pe . Graphics . FillRectangle ( SystemBrushes . Window , cr ) ;
if ( VisualStyleRenderer . IsSupported )
{
var btn = new VisualStyleRenderer ( VisualStyleElement . ScrollBar . ArrowButton . UpDisabled ) ;
var sz = btn . GetPartSize ( pe . Graphics , ThemeSizeType . True ) ;
var rsb = new Rectangle ( cr . X + cr . Width - sz . Width , cr . Y , sz . Width , cr . Height ) ;
new VisualStyleRenderer ( VisualStyleElement . ScrollBar . LowerTrackVertical . Disabled ) . DrawBackground ( pe . Graphics , rsb ) ;
rsb . Height = sz . Height ;
btn . DrawBackground ( pe . Graphics , rsb ) ;
rsb . Offset ( 0 , cr . Height - sz . Height ) ;
new VisualStyleRenderer ( VisualStyleElement . ScrollBar . ArrowButton . DownDisabled ) . DrawBackground ( pe . Graphics , rsb ) ;
}
else
{
var sz = new Size ( SystemInformation . VerticalScrollBarWidth , SystemInformation . VerticalScrollBarArrowHeight ) ;
var rsb = new Rectangle ( cr . X + cr . Width - sz . Width , cr . Y , sz . Width , cr . Height ) ;
pe . Graphics . FillRectangle ( SystemBrushes . ControlLightLight , rsb ) ;
rsb . Height = sz . Height ;
ControlPaint . DrawScrollButton ( pe . Graphics , rsb , ScrollButton . Up , ButtonState . Inactive ) ;
rsb . Offset ( 0 , cr . Height - sz . Height ) ;
ControlPaint . DrawScrollButton ( pe . Graphics , rsb , ScrollButton . Down , ButtonState . Inactive ) ;
}
ControlPaint . DrawBorder ( pe . Graphics , cr , SystemColors . WindowFrame , ButtonBorderStyle . Solid ) ;
using var font = new Font ( "Segoe UI" , 9 ) ;
using var sf = new StringFormat { Alignment = StringAlignment . Near , LineAlignment = StringAlignment . Near } ;
pe . Graphics . DrawString ( nameof ( ExplorerBrowser ) , font , SystemBrushes . GrayText , Rectangle . Inflate ( cr , - 3 , - 3 ) , sf ) ;
}
2023-12-30 19:50:35 -05:00
base . OnPaint ( pe ! ) ;
2023-09-29 13:58:35 -04:00
}
/// <summary>Sizes the native control to match the WinForms control wrapper.</summary>
/// <param name="e">Contains information about the size changed event.</param>
protected override void OnSizeChanged ( EventArgs e )
{
unsafe { explorerBrowserControl ? . SetRect ( default , ClientRectangle ) ; }
base . OnSizeChanged ( e ) ;
}
/// <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>
protected virtual void SetSite ( IServiceProvider ? sp ) = > ( explorerBrowserControl as IObjectWithSite ) ? . SetSite ( sp ) ;
private FOLDERVIEWMODE GetCurrentViewMode ( )
{
var fv2 = GetFolderView2 ( ) ;
return fv2 ? . GetCurrentViewMode ( ) ? ? 0 ;
}
private bool IsContentFlagSet ( ExplorerBrowserContentSectionOptions flag ) = > folderSettings . fFlags . IsFlagSet ( ( FOLDERFLAGS ) flag ) ;
private bool IsNavFlagSet ( ExplorerBrowserNavigateOptions flag ) = > NavigationFlags . IsFlagSet ( flag ) ;
/// <summary>Find the native control handle, remove its border style, then ask for a redraw.</summary>
private void RemoveWindowBorder ( )
{
// There is an option (EBO_NOBORDER) to avoid showing a border on the native ExplorerBrowser control so we wouldn't have to
// remove it afterwards, but:
// 1. It's not implemented by the Windows API Code Pack
// 2. The flag doesn't seem to work anyway (tested on 7 and 8.1) For reference: EXPLORER_BROWSER_OPTIONS https://msdn.microsoft.com/en-us/library/windows/desktop/bb762501(v=vs.85).aspx
var hwnd = FindWindowEx ( Handle , default , "ExplorerBrowserControl" , default ) ;
var explorerBrowserStyle = ( WindowStyles ) GetWindowLongAuto ( hwnd , WindowLongFlags . GWL_STYLE ) . ToInt32 ( ) ;
SetWindowLong ( hwnd , WindowLongFlags . GWL_STYLE , ( int ) explorerBrowserStyle . ClearFlags ( WindowStyles . WS_CAPTION | WindowStyles . WS_BORDER ) ) ;
SetWindowPos ( hwnd , default , 0 , 0 , 0 , 0 , SetWindowPosFlags . SWP_FRAMECHANGED | SetWindowPosFlags . SWP_NOMOVE | SetWindowPosFlags . SWP_NOSIZE ) ;
}
private void SetContentFlag ( ExplorerBrowserContentSectionOptions flag , bool value )
{
folderSettings . fFlags = folderSettings . fFlags . SetFlags ( ( FOLDERFLAGS ) flag , value ) ;
explorerBrowserControl ? . SetFolderSettings ( folderSettings ) ;
}
private void SetNavFlag ( ExplorerBrowserNavigateOptions flag , bool value ) = > NavigationFlags = NavigationFlags . SetFlags ( flag , value ) ;
private bool ShouldSerializePropertyBagName ( ) = > propertyBagName ! = defaultPropBagName ;
/// <summary>Controls the visibility of the various ExplorerBrowser panes on subsequent navigation</summary>
[TypeConverter(typeof(BetterExpandableObjectConverter)), Serializable]
public class ExplorerBrowserPaneVisibility
{
internal ExplorerBrowserPaneVisibility ( )
{
}
/// <summary>Additional fields and options to aid in a search.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("Additional fields and options to aid in a search.")]
public PaneVisibilityState AdvancedQuery { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>Commands module along the top of the Windows Explorer window.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("Commands module along the top of the Windows Explorer window.")]
public PaneVisibilityState Commands { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>Organize menu within the commands module.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("Organize menu within the commands module.")]
public PaneVisibilityState CommandsOrganize { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>View menu within the commands module.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("View menu within the commands module.")]
public PaneVisibilityState CommandsView { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>Pane showing metadata along the bottom of the Windows Explorer window.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("Pane showing metadata along the bottom of the Windows Explorer window.")]
public PaneVisibilityState Details { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>The pane on the left side of the Windows Explorer window that hosts the folders tree and Favorites.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("The pane on the left side of the Windows Explorer window that hosts the folders tree and Favorites.")]
public PaneVisibilityState Navigation { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>Pane on the right of the Windows Explorer window that shows a large reading preview of the file.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("Pane on the right of the Windows Explorer window that shows a large reading preview of the file.")]
public PaneVisibilityState Preview { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>Quick filter buttons to aid in a search.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("Quick filter buttons to aid in a search.")]
public PaneVisibilityState Query { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>
/// Introduced in Windows 8: The ribbon, which is the control that replaced menus and toolbars at the top of many Microsoft applications.
/// </summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("The ribbon, which is the control that replaced menus and toolbars at the top of many Microsoft applications.")]
public PaneVisibilityState Ribbon { get ; set ; } = PaneVisibilityState . Default ;
/// <summary>Introduced in Windows 8: A status bar that indicates the progress of some process, such as copying or downloading.</summary>
[DefaultValue(PaneVisibilityState.Default), Category("Appearance"), Description("A status bar that indicates the progress of some process, such as copying or downloading.")]
public PaneVisibilityState StatusBar { get ; set ; } = PaneVisibilityState . Default ;
}
/// <summary>Event argument for The Navigated event</summary>
public class NavigatedEventArgs : EventArgs
{
/// <summary>The new location of the explorer browser</summary>
public ShellItem ? NewLocation { get ; set ; }
}
/// <summary>Event argument for The Navigating event</summary>
public class NavigatingEventArgs : EventArgs
{
/// <summary>Set to 'True' to cancel the navigation.</summary>
public bool Cancel { get ; set ; }
/// <summary>The location being navigated to</summary>
public ShellItem ? PendingLocation { get ; set ; }
}
/// <summary>Event argument for the NavigatinoFailed event</summary>
public class NavigationFailedEventArgs : EventArgs
{
/// <summary>The location the browser would have navigated to.</summary>
public ShellItem ? FailedLocation { get ; set ; }
}
/// <summary>The navigation log is a history of the locations visited by the explorer browser.</summary>
public class NavigationLog
{
private readonly ExplorerBrowser ? parent = null ;
/// <summary>The pending navigation log action. null if the user is not navigating via the navigation log.</summary>
private PendingNavigation ? pendingNavigation ;
internal NavigationLog ( ExplorerBrowser parent )
{
// Hook navigation events from the parent to distinguish between navigation log induced navigation, and other navigations.
this . parent = parent ? ? throw new ArgumentNullException ( nameof ( parent ) ) ;
this . parent . Navigated + = OnNavigated ;
this . parent . NavigationFailed + = OnNavigationFailed ;
}
/// <summary>Fires when the navigation log changes or the current navigation position changes</summary>
public event EventHandler < NavigationLogEventArgs > ? NavigationLogChanged ;
/// <summary>Indicates the presence of locations in the log that can be reached by calling Navigate(Backward)</summary>
public bool CanNavigateBackward = > CurrentLocationIndex > 0 ;
/// <summary>Indicates the presence of locations in the log that can be reached by calling Navigate(Forward)</summary>
public bool CanNavigateForward = > CurrentLocationIndex < Locations . Count - 1 ;
/// <summary>Gets the shell object in the Locations collection pointed to by CurrentLocationIndex.</summary>
public ShellItem ? CurrentLocation = > CurrentLocationIndex < 0 ? null : Locations [ CurrentLocationIndex ] ;
/// <summary>
/// An index into the Locations collection. The ShellItem pointed to by this index is the current location of the ExplorerBrowser.
/// </summary>
public int CurrentLocationIndex { get ; set ; } = - 1 ;
/// <summary>The navigation log</summary>
public List < ShellItem > Locations { get ; } = new List < ShellItem > ( ) ;
/// <summary>Clears the contents of the navigation log.</summary>
public void Clear ( )
{
if ( Locations . Count = = 0 ) return ;
var oldCanNavigateBackward = CanNavigateBackward ;
var oldCanNavigateForward = CanNavigateForward ;
Locations . Clear ( ) ;
CurrentLocationIndex = - 1 ;
var args = new NavigationLogEventArgs
{
LocationsChanged = true ,
CanNavigateBackwardChanged = oldCanNavigateBackward ! = CanNavigateBackward ,
CanNavigateForwardChanged = oldCanNavigateForward ! = CanNavigateForward
} ;
NavigationLogChanged ? . Invoke ( this , args ) ;
}
internal bool NavigateLog ( NavigationLogDirection direction )
{
// determine proper index to navigate to
int locationIndex ;
switch ( direction )
{
case NavigationLogDirection . Backward when CanNavigateBackward :
locationIndex = CurrentLocationIndex - 1 ;
break ;
case NavigationLogDirection . Forward when CanNavigateForward :
locationIndex = CurrentLocationIndex + 1 ;
break ;
default :
return false ;
}
// initiate traversal request
var location = Locations [ locationIndex ] ;
pendingNavigation = new PendingNavigation ( location , locationIndex ) ;
parent ? . Navigate ( location ) ;
return true ;
}
internal bool NavigateLog ( int index )
{
// can't go anywhere
if ( index > = Locations . Count | | index < 0 ) return false ;
// no need to re navigate to the same location
if ( index = = CurrentLocationIndex ) return false ;
// initiate traversal request
var location = Locations [ index ] ;
pendingNavigation = new PendingNavigation ( location , index ) ;
parent ? . Navigate ( location ) ;
return true ;
}
private void OnNavigated ( object? sender , NavigatedEventArgs args )
{
var eventArgs = new NavigationLogEventArgs ( ) ;
var oldCanNavigateBackward = CanNavigateBackward ;
var oldCanNavigateForward = CanNavigateForward ;
if ( pendingNavigation ! = null )
{
// navigation log traversal in progress
// determine if new location is the same as the traversal request
var shellItemsEqual = pendingNavigation . Location . IShellItem . Compare ( args . NewLocation ? . IShellItem , SICHINTF . SICHINT_ALLFIELDS ) = = 0 ;
if ( ! shellItemsEqual )
{
// new location is different than traversal request, behave is if it never happened! remove history following
// currentLocationIndex, append new item
if ( CurrentLocationIndex < Locations . Count - 1 )
{
Locations . RemoveRange ( CurrentLocationIndex + 1 , Locations . Count - ( CurrentLocationIndex + 1 ) ) ;
}
if ( args . NewLocation is not null ) Locations . Add ( args . NewLocation ) ;
CurrentLocationIndex = Locations . Count - 1 ;
eventArgs . LocationsChanged = true ;
}
else
{
// log traversal successful, update index
CurrentLocationIndex = pendingNavigation . Index ;
eventArgs . LocationsChanged = false ;
}
pendingNavigation = null ;
}
else
{
// remove history following currentLocationIndex, append new item
if ( CurrentLocationIndex < Locations . Count - 1 )
{
Locations . RemoveRange ( CurrentLocationIndex + 1 , Locations . Count - ( CurrentLocationIndex + 1 ) ) ;
}
if ( args . NewLocation is not null ) Locations . Add ( args . NewLocation ) ;
CurrentLocationIndex = Locations . Count - 1 ;
eventArgs . LocationsChanged = true ;
}
// update event args
eventArgs . CanNavigateBackwardChanged = oldCanNavigateBackward ! = CanNavigateBackward ;
eventArgs . CanNavigateForwardChanged = oldCanNavigateForward ! = CanNavigateForward ;
NavigationLogChanged ? . Invoke ( this , eventArgs ) ;
}
private void OnNavigationFailed ( object? sender , NavigationFailedEventArgs args ) = > pendingNavigation = null ;
/// <summary>A navigation traversal request</summary>
private class PendingNavigation
{
internal PendingNavigation ( ShellItem location , int index )
{
Location = location ;
Index = index ;
}
internal int Index { get ; set ; }
internal ShellItem Location { get ; set ; }
}
}
/// <summary>The event argument for NavigationLogChangedEvent</summary>
public class NavigationLogEventArgs : EventArgs
{
/// <summary>Indicates CanNavigateBackward has changed</summary>
public bool CanNavigateBackwardChanged { get ; set ; }
/// <summary>Indicates CanNavigateForward has changed</summary>
public bool CanNavigateForwardChanged { get ; set ; }
/// <summary>Indicates the Locations collection has changed</summary>
public bool LocationsChanged { get ; set ; }
}
/// <summary>Represents a collection of <see cref="ShellItem"/> attached to an <see cref="ExplorerBrowser"/>.</summary>
private class ShellItemCollection : IReadOnlyList < ShellItem >
{
private readonly ExplorerBrowser eb ;
private readonly SVGIO option ;
internal ShellItemCollection ( ExplorerBrowser eb , SVGIO opt )
{
this . eb = eb ;
option = opt ;
}
/// <summary>Gets the number of elements in the collection.</summary>
/// <value>Returns a <see cref="int"/> value.</value>
public int Count
{
get
{
var fv2 = eb ? . GetFolderView2 ( ) ;
return fv2 ? . ItemCount ( option ) ? ? 0 ;
}
}
private IShellItemArray ? Array = > eb . GetItemsArray ( option ) ;
private IEnumerable < IShellItem > Items
{
get
{
var array = Array ;
if ( array is null )
yield break ;
try
{
for ( uint i = 0 ; i < array . GetCount ( ) ; i + + )
yield return array . GetItemAt ( i ) ;
}
finally
{
Marshal . ReleaseComObject ( array ) ;
}
}
}
/// <summary>Gets the <see cref="ShellItem"/> at the specified index.</summary>
/// <value>The <see cref="ShellItem"/>.</value>
/// <param name="index">The zero-based index of the element to get.</param>
public ShellItem this [ int index ]
{
get
{
var array = Array ? ? throw new InvalidOperationException ( "Unable to acquire access to shell item list." ) ;
try
{
return ShellItem . Open ( array . GetItemAt ( ( uint ) index ) ) ;
}
catch
{
throw new ArgumentOutOfRangeException ( nameof ( index ) ) ;
}
finally
{
Marshal . ReleaseComObject ( array ) ;
}
}
}
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
public IEnumerator < ShellItem > GetEnumerator ( ) = > Items . Select ( ShellItem . Open ) . GetEnumerator ( ) ;
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
IEnumerator IEnumerable . GetEnumerator ( ) = > GetEnumerator ( ) ;
}
/// <summary>This provides a connection point container compatible dispatch interface for hooking into the ExplorerBrowser view.</summary>
[ComVisible(true)]
2023-09-24 17:26:46 -04:00
[ClassInterface(ClassInterfaceType.AutoDual)]
private class ViewEvents : IDisposable
2023-09-29 13:58:35 -04:00
{
private static readonly Guid IID_DShellFolderViewEvents = typeof ( DShellFolderViewEvents ) . GUID ;
private static readonly Guid IID_IDispatch = typeof ( OleAut32 . IDispatch ) . GUID ;
private readonly ExplorerBrowser parent ;
private uint viewConnectionPointCookie ;
private object? viewDispatch ;
internal ViewEvents ( ExplorerBrowser parent ) = > this . parent = parent ;
// Prevent default construction
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private ViewEvents ( ) { }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
/// <summary>Finalizes ViewEvents</summary>
~ ViewEvents ( )
{
Dispose ( false ) ;
}
/// <summary>Disconnects and disposes object.</summary>
public void Dispose ( )
{
Dispose ( true ) ;
System . GC . SuppressFinalize ( this ) ;
}
/// <summary>The contents of the view have changed</summary>
[DispId(DISPID.DISPID_CONTENTSCHANGED)]
public void ViewContentsChanged ( ) = > parent . OnItemsChanged ( ) ;
/// <summary>The enumeration of files in the view is complete</summary>
[DispId(DISPID.DISPID_FILELISTENUMDONE)]
public void ViewFileListEnumDone ( ) = > parent . OnItemsEnumerated ( ) ;
/// <summary>The selected item in the view has changed (not the same as the selection has changed)</summary>
[DispId(DISPID.DISPID_SELECTEDITEMCHANGED)]
public void ViewSelectedItemModified ( ) = > parent . OnSelectedItemModified ( ) ;
/// <summary>The view selection has changed</summary>
[DispId(DISPID.DISPID_SELECTIONCHANGED)]
public void ViewSelectionChanged ( ) = > parent . OnSelectionChanged ( ) ;
internal void ConnectToView ( IShellView psv )
{
DisconnectFromView ( ) ;
viewDispatch = psv . GetItemObject ( SVGIO . SVGIO_BACKGROUND , IID_IDispatch ) ;
#pragma warning disable IL2050 // Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed.
if ( viewDispatch is not null & & ConnectToConnectionPoint ( this , IID_DShellFolderViewEvents , true , viewDispatch , ref viewConnectionPointCookie ) . Failed )
{
viewDispatch = null ;
}
#pragma warning restore IL2050 // Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed.
}
internal void DisconnectFromView ( )
{
if ( viewDispatch is null ) return ;
#pragma warning disable IL2050 // Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed.
ConnectToConnectionPoint ( null , IID_DShellFolderViewEvents , false , viewDispatch , ref viewConnectionPointCookie ) ;
#pragma warning restore IL2050 // Correctness of COM interop cannot be guaranteed after trimming. Interfaces and interface members might be removed.
viewDispatch = null ;
viewConnectionPointCookie = 0 ;
}
// These need to be public to be accessible via AutoDual reflection
/// <summary>Disconnects and disposes object.</summary>
/// <param name="disposed"></param>
protected virtual void Dispose ( bool disposed )
{
if ( disposed )
{
DisconnectFromView ( ) ;
}
}
}
}