c# propertygrid folderbrowserdialog

c# - Mostrar el Explorador de carpetas detallado de un PropertyGrid



folderbrowserdialog (2)

Aquí hay un UITypeEditor personalizado que le permite usar el Explorador de carpetas de Vista:

Puedes usarlo como cualquier otro editor:

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

Se basa en una clase personalizada FolderBrowser2 que he escrito para la ocasión. Por supuesto, esto funcionará solo en Windows Vista y superior. En la versión anterior de Windows, no hay otro navegador de carpetas que el 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 = string.Format("{0}", value); } if (browser.ShowDialog(null) == DialogResult.OK) return browser.DirectoryPath; return value; } } public class FolderBrowser2 { public string DirectoryPath { get; set; } public DialogResult ShowDialog(IWin32Window owner) { IntPtr hwndOwner = owner != null ? owner.Handle : GetActiveWindow(); IFileOpenDialog dialog = (IFileOpenDialog)new FileOpenDialog(); try { IShellItem item; if (!string.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); string 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)] string 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)] string pszName); void GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName); void SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle); void SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText); void SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel); void GetResult(out IShellItem ppsi); void AddPlace(IShellItem psi, int alignment); void SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string 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 string ppszName); void GetAttributes(); // 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 } }

Tenga en cuenta que no es una pregunta duplicada.

Cómo mostrar un FolderBrowser detallado como en la imagen de abajo de un PropertyGrid (del campo / propiedad que tiene puntos suspensivos ...)

Utilizando

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

Obtenemos el navegador de carpetas minimalistas.


Aquí hay una solución que hace el mismo trabajo que la respuesta de Simon Mourier, sin usar directamente interoperabilidad (.Net se encarga de eso por usted). Tiene la característica adicional de volver al cuadro de diálogo pre-Vista si no está en una versión de Windows lo suficientemente alta. Debería funcionar en Windows 7, 8, 10 y superior (teóricamente).

Hay una gran advertencia: Microsoft es libre de cambiar sus clases internas a voluntad. Ya que esto utiliza Reflection para anular las reglas de alcance y esta acción no es compatible (Microsoft solo está interesado en lo que está expuesto públicamente), este código podría romperse si Microsoft realiza cambios.

using System; using System.Reflection; using System.Windows.Forms; namespace ErikE.Shuriken { /// <summary> /// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions /// </summary> public class FolderSelectDialog { private string _initialDirectory; private string _title; private string _fileName = ""; public string InitialDirectory { get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; } set { _initialDirectory = value; } } public string Title { get { return _title ?? "Select a folder"; } set { _title = value; } } public string FileName { get { return _fileName; } } public bool Show() { return Show(IntPtr.Zero); } /// <param name="hWndOwner">Handle of the control or window to be the parent of the file dialog</param> /// <returns>true if the user clicks OK</returns> 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 string FileName { get; set; } } private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string 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 string 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, string initialDirectory, string 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; } } } } }

Desarrollé esto como una versión limpia de .NET Win 7-style folder select dialog por Bill Seddon de lyquidity.com (no tengo afiliación). Escribí la mía porque su solución requiere una clase de Reflexión adicional que no es necesaria para este propósito enfocado, usa el control de flujo basado en excepciones, no almacena en caché los resultados de sus llamadas de reflexión. Tenga en cuenta que la clase VistaDialog estática anidada es para que sus variables de reflexión estática no intenten completarse si nunca se llama al método Show .

Se usa como tal en un formulario de Windows:

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

Por supuesto, puedes jugar con sus opciones y las propiedades que expone. Por ejemplo, permite la selección múltiple en el cuadro de diálogo de estilo Vista.