Afficher le navigateur de dossiers détaillé à partir d’un PropertyGrid

S’il vous plaît noter que ce n’est pas une question en double.

Comment afficher un FolderBrowser détaillé comme dans l’image ci-dessous à partir d’un PropertyGrid (à partir du champ / de la propriété qui a des ellipses …) Navigateur de dossiers détaillé

En utilisant

[EditorAtsortingbute(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(System.Drawing.Design.UITypeEditor))] [EditorAtsortingbute(typeof(System.Windows.Forms.Design.FolderNameEditor), typeof(System.Drawing.Design.UITypeEditor))] 

Nous obtenons le navigateur de dossiers minimaliste

Navigateur de dossiers minimaliste

Voici un UITypeEditor personnalisé qui vous permet d’utiliser le navigateur de dossiers Vista:

entrez la description de l'image ici

Vous pouvez l’utiliser comme n’importe quel autre éditeur:

 [EditorAtsortingbute(typeof(FolderNameEditor2), typeof(System.Drawing.Design.UITypeEditor))] 

Il repose sur une classe FolderBrowser2 personnalisée que j’ai écrite pour l’occasion. Bien entendu, cela ne fonctionnera que sous Windows Vista et supérieur. Sur la version précédente de Windows, il n’existait pas d’autre navigateur de dossiers que le simple.

 public class FolderNameEditor2 : UITypeEditor { public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { return UITypeEditorEditStyle.Modal; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { FolderBrowser2 browser = new FolderBrowser2(); if (value != null) { browser.DirectoryPath = ssortingng.Format("{0}", value); } if (browser.ShowDialog(null) == DialogResult.OK) return browser.DirectoryPath; return value; } } public class FolderBrowser2 { public ssortingng DirectoryPath { get; set; } public DialogResult ShowDialog(IWin32Window owner) { IntPtr hwndOwner = owner != null ? owner.Handle : GetActiveWindow(); IFileOpenDialog dialog = (IFileOpenDialog)new FileOpenDialog(); try { IShellItem item; if (!ssortingng.IsNullOrEmpty(DirectoryPath)) { IntPtr idl; uint atts = 0; if (SHILCreateFromPath(DirectoryPath, out idl, ref atts) == 0) { if (SHCreateShellItem(IntPtr.Zero, IntPtr.Zero, idl, out item) == 0) { dialog.SetFolder(item); } Marshal.FreeCoTaskMem(idl); } } dialog.SetOptions(FOS.FOS_PICKFOLDERS | FOS.FOS_FORCEFILESYSTEM); uint hr = dialog.Show(hwndOwner); if (hr == ERROR_CANCELLED) return DialogResult.Cancel; if (hr != 0) return DialogResult.Abort; dialog.GetResult(out item); ssortingng path; item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out path); DirectoryPath = path; return DialogResult.OK; } finally { Marshal.ReleaseComObject(dialog); } } [DllImport("shell32.dll")] private static extern int SHILCreateFromPath([MarshalAs(UnmanagedType.LPWStr)] ssortingng pszPath, out IntPtr ppIdl, ref uint rgflnOut); [DllImport("shell32.dll")] private static extern int SHCreateShellItem(IntPtr pidlParent, IntPtr psfParent, IntPtr pidl, out IShellItem ppsi); [DllImport("user32.dll")] private static extern IntPtr GetActiveWindow(); private const uint ERROR_CANCELLED = 0x800704C7; [ComImport] [Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")] private class FileOpenDialog { } [ComImport] [Guid("42f85136-db7e-439c-85f1-e4075d135fc8")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IFileOpenDialog { [PreserveSig] uint Show([In] IntPtr parent); // IModalWindow void SetFileTypes(); // not fully defined void SetFileTypeIndex([In] uint iFileType); void GetFileTypeIndex(out uint piFileType); void Advise(); // not fully defined void Unadvise(); void SetOptions([In] FOS fos); void GetOptions(out FOS pfos); void SetDefaultFolder(IShellItem psi); void SetFolder(IShellItem psi); void GetFolder(out IShellItem ppsi); void GetCurrentSelection(out IShellItem ppsi); void SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] ssortingng pszName); void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out ssortingng pszName); void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] ssortingng pszTitle); void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] ssortingng pszText); void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] ssortingng pszLabel); void GetResult(out IShellItem ppsi); void AddPlace(IShellItem psi, int alignment); void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] ssortingng pszDefaultExtension); void Close(int hr); void SetClientGuid(); // not fully defined void ClearClientData(); void SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter); void GetResults([MarshalAs(UnmanagedType.Interface)] out IntPtr ppenum); // not fully defined void GetSelectedItems([MarshalAs(UnmanagedType.Interface)] out IntPtr ppsai); // not fully defined } [ComImport] [Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IShellItem { void BindToHandler(); // not fully defined void GetParent(); // not fully defined void GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out ssortingng ppszName); void GetAtsortingbutes(); // not fully defined void Compare(); // not fully defined } private enum SIGDN : uint { SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, SIGDN_FILESYSPATH = 0x80058000, SIGDN_NORMALDISPLAY = 0, SIGDN_PARENTRELATIVE = 0x80080001, SIGDN_PARENTRELATIVEEDITING = 0x80031001, SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, SIGDN_PARENTRELATIVEPARSING = 0x80018001, SIGDN_URL = 0x80068000 } [Flags] private enum FOS { FOS_ALLNONSTORAGEITEMS = 0x80, FOS_ALLOWMULTISELECT = 0x200, FOS_CREATEPROMPT = 0x2000, FOS_DEFAULTNOMINIMODE = 0x20000000, FOS_DONTADDTORECENT = 0x2000000, FOS_FILEMUSTEXIST = 0x1000, FOS_FORCEFILESYSTEM = 0x40, FOS_FORCESHOWHIDDEN = 0x10000000, FOS_HIDEMRUPLACES = 0x20000, FOS_HIDEPINNEDPLACES = 0x40000, FOS_NOCHANGEDIR = 8, FOS_NODEREFERENCELINKS = 0x100000, FOS_NOREADONLYRETURN = 0x8000, FOS_NOTESTFILECREATE = 0x10000, FOS_NOVALIDATE = 0x100, FOS_OVERWRITEPROMPT = 2, FOS_PATHMUSTEXIST = 0x800, FOS_PICKFOLDERS = 0x20, FOS_SHAREAWARE = 0x4000, FOS_STRICTFILETYPES = 4 } } 

Voici une solution qui fait le même travail que la réponse de Simon Mourier, sans utiliser directement interop (.Net s’en charge pour vous). Il a la particularité supplémentaire de revenir à la boîte de dialog antérieure à Vista si la version de Windows n’est pas assez élevée. Devrait fonctionner sous Windows 7, 8, 10 et supérieur (en théorie).

Il y a un gros inconvénient: Microsoft est libre de changer ses classes internes à volonté. Dans la mesure où cela utilise Reflection pour contourner les règles de scope et que cette action n’est pas prise en charge (Microsoft s’intéresse uniquement à ce qui est exposé publiquement), ce code peut échouer si Microsoft apporte des modifications.

 using System; using System.Reflection; using System.Windows.Forms; namespace ErikE.Shuriken { ///  /// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions ///  public class FolderSelectDialog { private ssortingng _initialDirectory; private ssortingng _title; private ssortingng _fileName = ""; public ssortingng InitialDirectory { get { return ssortingng.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; } set { _initialDirectory = value; } } public ssortingng Title { get { return _title ?? "Select a folder"; } set { _title = value; } } public ssortingng FileName { get { return _fileName; } } public bool Show() { return Show(IntPtr.Zero); } /// Handle of the control or window to be the parent of the file dialog /// true if the user clicks OK public bool Show(IntPtr hWndOwner) { var result = Environment.OSVersion.Version.Major >= 6 ? VistaDialog.Show(hWndOwner, InitialDirectory, Title) : ShowXpDialog(hWndOwner, InitialDirectory, Title); _fileName = result.FileName; return result.Result; } private struct ShowDialogResult { public bool Result { get; set; } public ssortingng FileName { get; set; } } private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, ssortingng initialDirectory, ssortingng title) { var folderBrowserDialog = new FolderBrowserDialog { Description = title, SelectedPath = initialDirectory, ShowNewFolderButton = false }; var dialogResult = new ShowDialogResult(); if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK) { dialogResult.Result = true; dialogResult.FileName = folderBrowserDialog.SelectedPath; } return dialogResult; } private static class VistaDialog { private const ssortingng c_foldersFilter = "Folders|\n"; private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly; private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog"); private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags); private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags); private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags); private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags); private readonly static uint s_fosPickFoldersBitFlag = (uint) s_windowsFormsAssembly .GetType("System.Windows.Forms.FileDialogNative+FOS") .GetField("FOS_PICKFOLDERS") .GetValue(null); private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly .GetType("System.Windows.Forms.FileDialog+VistaDialogEvents") .GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null); private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise"); private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise"); private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show"); public static ShowDialogResult Show(IntPtr ownerHandle, ssortingng initialDirectory, ssortingng title) { var openFileDialog = new OpenFileDialog { AddExtension = false, CheckFileExists = false, DereferenceLinks = true, Filter = c_foldersFilter, InitialDirectory = initialDirectory, Multiselect = false, Title = title }; var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { }); s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog }); s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint) s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag }); var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U }; s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken); try { int retVal = (int) s_showMethodInfo.Invoke(iFileDialog, new object[] { ownerHandle }); return new ShowDialogResult { Result = retVal == 0, FileName = openFileDialog.FileName }; } finally { s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] }); } } } // Wrap an IWin32Window around an IntPtr private class WindowWrapper : IWin32Window { private readonly IntPtr _handle; public WindowWrapper(IntPtr handle) { _handle = handle; } public IntPtr Handle { get { return _handle; } } } } } 

J’ai développé cela comme une version nettoyée de la boîte de dialog de sélection de dossier .NET Win 7-style par Bill Seddon de lyquidity.com (je n’ai aucune affiliation). J’ai écrit le mien car sa solution nécessite une classe Reflection supplémentaire qui n’est pas nécessaire à cette fin, utilise un contrôle de stream basé sur des exceptions, ne met pas en cache les résultats de ses appels de reflection. Notez que la classe VistaDialog statique nestede est telle que ses variables de reflection statique n’essayent pas d’être renseignées si la méthode Show n’est jamais appelée.

Il est utilisé comme tel dans un Windows Form:

 var dialog = new FolderSelectDialog { InitialDirectory = musicFolderTextBox.Text Title = "Select a folder to import music from" }; if (dialog.Show(Handle)) { musicFolderTextBox.Text = dialog.FileName; } 

Vous pouvez bien sûr jouer avec ses options et les propriétés qu’il expose. Par exemple, il permet la sélection multiple dans la boîte de dialog de style Vista.