【问题标题】:Browse for a directory in C#在 C# 中浏览目录
【发布时间】:2010-09-05 22:07:00
【问题描述】:

我如何向用户展示一个允许他/她选择目录的控件?

似乎没有任何本地 .net 控件可以执行此操作?

【问题讨论】:

    标签: c# .net directory


    【解决方案1】:

    FolderBrowserDialog class 是最佳选择。

    【讨论】:

    • 在 System.Windows.Forms Dll 中
    【解决方案2】:

    您可以只使用 System.Windows.Forms 命名空间中的 FolderBrowserDialog 类。

    【讨论】:

      【解决方案3】:

      请不要尝试使用 TreeView/DirectoryInfo 类自行开发。一方面,您可以使用 SHBrowseForFolder 免费获得许多不错的功能(图标/右键单击/网络)。另一方面,您可能不会意识到一些边缘情况/问题。

      【讨论】:

        【解决方案4】:
        string folderPath = "";
        FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog();
        if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) {
            folderPath = folderBrowserDialog1.SelectedPath ;
        }
        

        【讨论】:

        • 不要忘记使用 using(FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog())
        • 它工作正常请告诉我选择路径后如何关闭窗口浏览器?现在路径得到多次选择** C:\Users\Centric\Downloads\wordlistsC:\Users\Centric\Downloads\wordlistsC:\Users\Centric\Desktop** 它应该是这样的 ** C:\Users\ Centric\Downloads\wordlists** @Chandima
        【解决方案5】:

        注意:不能保证此代码将在 .Net 框架的未来版本中工作。在这里通过反射使用私有 .Net 框架内部可能并不好。使用底部提到的互操作解决方案,因为 Windows API 不太可能更改。

        如果您正在寻找一个看起来更像 Windows 7 对话框的文件夹选择器,并且能够从底部的文本框和左侧的导航窗格中复制和粘贴收藏夹和常用位置,那么您可以获得以非常轻量级的方式访问它。

        FolderBrowserDialog UI 非常小:

        但你可以用这个代替:

        这是一个使用 .Net 私有IFileDialog 接口打开 Vista 风格的文件夹选择器的类,无需直接在代码中使用互操作(.Net 会为您处理)。如果 Windows 版本不够高,它会退回到 Vista 之前的对话框。应该在 Windows 7、8、9、10 和更高版本(理论上)中工作。

        using System;
        using System.Reflection;
        using System.Windows.Forms;
        
        namespace MyCoolCompany.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; } }
                }
            }
        }
        

        我将其开发为lyquidity.com 的比尔·塞登(Bill Seddon)的清理版.NET Win 7-style folder select dialog(我没有隶属关系)。我自己编写了自己的解决方案,因为他的解决方案需要一个额外的 Reflection 类,该类不需要这个重点目的,使用基于异常的流控制,不缓存其反射调用的结果。请注意,嵌套的静态 VistaDialog 类是这样的,如果从未调用过 Show 方法,则不会尝试填充其静态反射变量。

        在 Windows 窗体中这样使用:

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

        您当然可以使用它的选项以及它公开的属性。例如,它允许在 Vista 风格的对话框中进行多选。

        另外,请注意 Simon Mourier gave an answer 显示了如何直接使用互操作对 Windows API 执行完全相同的工作,但如果在旧版本的 Windows 中,必须补充他的版本以使用旧样式对话框。不幸的是,当我制定解决方案时,我还没有找到他的帖子。命名你的毒药!

        【讨论】:

          【解决方案6】:

          或者更好的是,你可以把这段代码放在一个类文件中

          using System;
          using System.IO;
          using System.Runtime.CompilerServices;
          using System.Runtime.InteropServices;
          using System.Windows.Forms;
          
          internal class OpenFolderDialog : IDisposable {
          
              /// <summary>
              /// Gets/sets folder in which dialog will be open.
              /// </summary>
              public string InitialFolder { get; set; }
          
              /// <summary>
              /// Gets/sets directory in which dialog will be open if there is no recent directory available.
              /// </summary>
              public string DefaultFolder { get; set; }
          
              /// <summary>
              /// Gets selected folder.
              /// </summary>
              public string Folder { get; private set; }
          
          
              internal DialogResult ShowDialog(IWin32Window owner) {
                  if (Environment.OSVersion.Version.Major >= 6) {
                      return ShowVistaDialog(owner);
                  } else {
                      return ShowLegacyDialog(owner);
                  }
              }
          
              private DialogResult ShowVistaDialog(IWin32Window owner) {
                  var frm = (NativeMethods.IFileDialog)(new NativeMethods.FileOpenDialogRCW());
                  uint options;
                  frm.GetOptions(out options);
                  options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
                  frm.SetOptions(options);
                  if (this.InitialFolder != null) {
                      NativeMethods.IShellItem directoryShellItem;
                      var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
                      if (NativeMethods.SHCreateItemFromParsingName(this.InitialFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK) {
                          frm.SetFolder(directoryShellItem);
                      }
                  }
                  if (this.DefaultFolder != null) {
                      NativeMethods.IShellItem directoryShellItem;
                      var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
                      if (NativeMethods.SHCreateItemFromParsingName(this.DefaultFolder, IntPtr.Zero, ref riid, out directoryShellItem) == NativeMethods.S_OK) {
                          frm.SetDefaultFolder(directoryShellItem);
                      }
                  }
          
                  if (frm.Show(owner.Handle) == NativeMethods.S_OK) {
                      NativeMethods.IShellItem shellItem;
                      if (frm.GetResult(out shellItem) == NativeMethods.S_OK) {
                          IntPtr pszString;
                          if (shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH, out pszString) == NativeMethods.S_OK) {
                              if (pszString != IntPtr.Zero) {
                                  try {
                                      this.Folder = Marshal.PtrToStringAuto(pszString);
                                      return DialogResult.OK;
                                  } finally {
                                      Marshal.FreeCoTaskMem(pszString);
                                  }
                              }
                          }
                      }
                  }
                  return DialogResult.Cancel;
              }
          
              private DialogResult ShowLegacyDialog(IWin32Window owner) {
                  using (var frm = new SaveFileDialog()) {
                      frm.CheckFileExists = false;
                      frm.CheckPathExists = true;
                      frm.CreatePrompt = false;
                      frm.Filter = "|" + Guid.Empty.ToString();
                      frm.FileName = "any";
                      if (this.InitialFolder != null) { frm.InitialDirectory = this.InitialFolder; }
                      frm.OverwritePrompt = false;
                      frm.Title = "Select Folder";
                      frm.ValidateNames = false;
                      if (frm.ShowDialog(owner) == DialogResult.OK) {
                          this.Folder = Path.GetDirectoryName(frm.FileName);
                          return DialogResult.OK;
                      } else {
                          return DialogResult.Cancel;
                      }
                  }
              }
          
          
              public void Dispose() { } //just to have possibility of Using statement.
          
          }
          
          internal static class NativeMethods {
          
              #region Constants
          
              public const uint FOS_PICKFOLDERS = 0x00000020;
              public const uint FOS_FORCEFILESYSTEM = 0x00000040;
              public const uint FOS_NOVALIDATE = 0x00000100;
              public const uint FOS_NOTESTFILECREATE = 0x00010000;
              public const uint FOS_DONTADDTORECENT = 0x02000000;
          
              public const uint S_OK = 0x0000;
          
              public const uint SIGDN_FILESYSPATH = 0x80058000;
          
              #endregion
          
          
              #region COM
          
              [ComImport, ClassInterface(ClassInterfaceType.None), TypeLibType(TypeLibTypeFlags.FCanCreate), Guid("DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7")]
              internal class FileOpenDialogRCW { }
          
          
              [ComImport(), Guid("42F85136-DB7E-439C-85F1-E4075D135FC8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
              internal interface IFileDialog {
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  [PreserveSig()]
                  uint Show([In, Optional] IntPtr hwndOwner); //IModalWindow 
          
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetFileTypes([In] uint cFileTypes, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr rgFilterSpec);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetFileTypeIndex([In] uint iFileType);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetFileTypeIndex(out uint piFileType);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint Advise([In, MarshalAs(UnmanagedType.Interface)] IntPtr pfde, out uint pdwCookie);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint Unadvise([In] uint dwCookie);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetOptions([In] uint fos);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetOptions(out uint fos);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  void SetDefaultFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetFolder([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetFolder([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetCurrentSelection([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetFileName([In, MarshalAs(UnmanagedType.LPWStr)] string pszName);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetTitle([In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetOkButtonLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszText);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetFileNameLabel([In, MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetResult([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint AddPlace([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, uint fdap);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetDefaultExtension([In, MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint Close([MarshalAs(UnmanagedType.Error)] uint hr);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetClientGuid([In] ref Guid guid);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint ClearClientData();
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint SetFilter([MarshalAs(UnmanagedType.Interface)] IntPtr pFilter);
              }
          
          
              [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
              internal interface IShellItem {
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint BindToHandler([In] IntPtr pbc, [In] ref Guid rbhid, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IntPtr ppvOut);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetDisplayName([In] uint sigdnName, out IntPtr ppszName);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs);
          
                  [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
                  uint Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder);
              }
          
              #endregion
          
          
              [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
              internal static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem ppv);
          
          }
          

          并像这样使用它

          using (var frm = new OpenFolderDialog()) {
                          if (frm.ShowDialog(this)== DialogResult.OK) {
                              MessageBox.Show(this, frm.Folder);
                          }
                      }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-09-07
            • 1970-01-01
            • 2011-04-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多