441

I was going to use the following project: https://github.com/scottwis/OpenFileOrFolderDialog

However, there's a problem: it uses the GetOpenFileName function and OPENFILENAME structure. OPENFILENAME has the member named templateID, which is the identifier for dialog template. And the project contains the res1.rc file and the templated dialog init, too. But I couldn't figure out how to attach this file to my C# project.

Is there a better way to use an OpenFileDialog to select folders?

jordanz
  • 367
  • 4
  • 12
Yun
  • 5,233
  • 4
  • 21
  • 38
  • If you open the project file with editor, you will notice some additional properties at the bottom: , and . You will see that it runs rc.exe to compile the resource file res1.rc (be sure to copy the "resource.h" too into your project). Make sure you have VisualC installed and that VCIncludePath points to a proper location (github's one points to VC9.0 version, and you may need to change it). After compiling .rc file, the resulting .res file is added as the resource for your executable with Win32Resource directive. – mistika Jun 24 '14 at 15:07
  • 3
    There is a hackish solution using OpenFileDialog where `ValidateNames` and `CheckFileExists` are both set to false and `FileName` is given a mock value to indicate that a directory is selected. I say hack because it is confusing to users about how to select a folder. See [Select file or folder from the same dialog](http://www.codeproject.com/Articles/44914/Select-file-or-folder-from-the-same-dialog) – Daniel Ballinger May 07 '15 at 03:28
  • Possible duplicate of [How do you configure an OpenFileDialog to select folders?](http://stackoverflow.com/questions/31059/how-do-you-configure-an-openfiledialog-to-select-folders) – WonderWorker Apr 14 '16 at 14:13
  • 1
    Thanx Dan for pointing towards the OpenFileDialog-Hack! That is wayy better than FolderBrowserDialog, because OFD shows bookmarked folders etc, so everyone - especially in bigger companies - finds their crap. FBD will not do much good in those places. – JayC667 Sep 16 '16 at 14:19
  • @DanielBallinger I am really interested in getting your method to work, but when opening the dialog, selecting a folder, hitting open, then open a second time gives an error dialog saying "file not found", not sure why it is trying to find the file after CheckFileExists was set to false – ComradeJoecool May 10 '18 at 00:10
  • 1
    @ComradeJoecool I've converted my comment to an [answer](https://stackoverflow.com/a/50263779/54026). I tried it several times and didn't have a "file not found" issue. Are you reusing the same OpenFileDialog instance? – Daniel Ballinger May 10 '18 at 00:21
  • 1
    @DanielBallinger ah, I found my issue, since I am using Powershell to create the dialog, setting `ValidateNames` and `CheckFileExists` to `false` was not working, I needed to set them to `0` (or learn powershell better) – ComradeJoecool May 10 '18 at 00:31
  • I think this nuget package is a good choice [BetterFolderBrowser](https://www.nuget.org/packages/BetterFolderBrowser) – live2 May 31 '19 at 07:54
  • I would ***strongly*** suggest changing the selected answer [Simon Mourier's answer](https://stackoverflow.com/a/66187224/4760737) as the accepted answer. I have implemented his solution (from finding it elsewhere, only to find out he posted here just a few days ago), and it works amazingly well. – pmackni Jul 15 '21 at 21:00
  • I shared another working answer here: https://stackoverflow.com/a/76245608/8458887 – Hellboy. May 14 '23 at 15:03

12 Answers12

515

Basically you need the FolderBrowserDialog class:

Prompts the user to select a folder. This class cannot be inherited.

Example:

using(var fbd = new FolderBrowserDialog())
{
    DialogResult result = fbd.ShowDialog();

    if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
    {
        string[] files = Directory.GetFiles(fbd.SelectedPath);

        System.Windows.Forms.MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
    }
}

If you work in WPF you have to add the reference to System.Windows.Forms.

you also have to add using System.IO for Directory class

Cee McSharpface
  • 8,493
  • 3
  • 36
  • 77
Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474
  • 263
    FolderBrowserDialog's lacks usability. The main disadvantage is that it doesn't allow you to copy a folder path from Windows Explorer for quick navigation, making it useless when you need to drill down more than three levels. Drilling into each folder is not desired especially when the storage is slow or when you have a lot of folders at one of the levels. – mistika Jun 24 '14 at 15:25
  • 26
    The question is specifically about using the OpenFileDialog (OFD) to select a folder, not the FolderBrowserDialog (FBD). I concur that the FBD is awful from a user standpoint. – Michael Paulukonis Apr 28 '15 at 15:09
  • 44
    Alternatively to this dialog with broken UI, use a **CommonOpenFileDialog**: `new CommonOpenFileDialog { IsFolderPicker = true }`. – ANeves Jun 12 '15 at 18:06
  • 176
    Please, **don't ever use it**! I remember as a user I was blaming these poor programmers that made yet another app with this awful *tree view dialog* *(which is just the FolderBrowserDialog)*. It is completely unusable: a bunch of root dirs, a missing favorites panel, and the most horrible — you can't even paste a path there! And now as a programmer I see an advice to use it… Please, don't do it. – Hi-Angel Aug 19 '15 at 13:12
  • 8
    FolderBrowserDialog has one big flaw besides everything else that the other users said. It does not remember the last selected path! – AleX_ Nov 18 '16 at 22:46
  • 11
    Note that `FolderBrowserDialog` uses [`SHBrowseForFolder`](https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shbrowseforfoldera) behind the scenes. The docs for this function specifically state, *"For Windows Vista or later, it is recommended that you use `IFileDialog` with the `FOS_PICKFOLDERS` option rather than the `SHBrowseForFolder` function. This uses the Open Files dialog in pick folders mode and is the preferred implementation."* So in addition to all the usability issues, it hasn't been the recommended solution since Vista, which came out in **2006**! – Herohtar Nov 22 '19 at 20:23
  • 10
    With .NET Core 3 `FolderBrowserDialog` will have the same UI as the one in WindowsAPICodePack. https://learn.microsoft.com/en-us/dotnet/core/porting/winforms-breaking-changes – Yusuf Tarık Günaydın Jan 12 '20 at 12:53
  • Is there any way to get the save file dialog which is already opened ? like we do with forms Application.OpenForms – Jay Aug 13 '20 at 10:51
  • @Herohtar I am in the process of testing it, but if this works this should honestly be the selected answer even above some of the other very useful posted answers. – pmackni Jul 15 '21 at 17:42
454

As a note for future users who would like to avoid using FolderBrowserDialog, Microsoft once released an API called the WindowsAPICodePack that had a helpful dialog called CommonOpenFileDialog, that could be set into a IsFolderPicker mode. The API is available from Microsoft as a NuGet package.

This is all I needed to install and use the CommonOpenFileDialog. (NuGet handled the dependencies)

Install-Package Microsoft.WindowsAPICodePack-Shell

For the include line:

using Microsoft.WindowsAPICodePack.Dialogs;

Usage:

CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = "C:\\Users";
dialog.IsFolderPicker = true;
if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
{
    MessageBox.Show("You selected: " + dialog.FileName);
}
Keith Stein
  • 6,235
  • 4
  • 17
  • 36
Joe
  • 4,710
  • 1
  • 11
  • 7
  • 62
    I think this is the nearest answer to "How to use OpenFileDialog to select a folder?" FolderBrowseDialog is very unusable. Thank you for this answer. – Koray Mar 30 '17 at 08:52
  • 61
    This should be the answer. And note that you need to install the `Microsoft.WindowsAPICodePack.Shell` package through NuGet before you can use this `CommonOpenFileDialog`. – smwikipedia Aug 21 '17 at 03:12
  • 1
    after selecting a folder, the dialog closes and disposes of 'form' if the 'form' is opened from another parent form using `showDialog()` method instead of `show()` method, i managed to solve the issue by using show() instead of show() and set Focus() on the calling form of the commonOpenFileDialog object. – Rakibul Haq Nov 30 '17 at 09:34
  • 4
    If you use this with VS2017 it restyles your main window. – Lokiare Aug 10 '18 at 17:46
  • nice find. Not sure why Microsoft doesn't include this in their main VS libraires. – 00jt Aug 19 '18 at 01:14
  • 1
    Note for `FolderBrowserDialog` users: multiple simultaneous instance usage of it can create problems. This `CommonOpenFileDialog` is better. – Alper Jan 21 '19 at 13:25
  • 17
    Microsoft seems to have republished it as `WindowsAPICodePack-Shell` – NucS Dec 16 '19 at 21:59
  • Just wrap in using statement, as it has inherited IDisposable – Vinnie Amir Apr 09 '20 at 03:51
  • @Lokiare this fixes the resizing problem https://stackoverflow.com/questions/42975285/commonopenfiledialog-cause-windows-form-to-shrink – JumpingJezza May 21 '20 at 07:34
  • Sadly when i use this it fails to load the assembly, despite it being included with my build. – Reahreic Jun 29 '20 at 19:43
  • 1
    As others have said, this should be the accepted answer, as it works perfectly and avoids using the horrible/unusable FolderBrowserDialog. – Fernando Aires Castello Oct 01 '20 at 02:57
  • 7
    The NuGet package linked wasn't working for me in .NET 5 as it failed to load the assembly. Using [Microsoft-WindowsAPICodePack-Shell](https://www.nuget.org/packages/Microsoft-WindowsAPICodePack-Shell/1.1.4?_src=template) did work though. – Dan Jan 10 '21 at 23:41
  • If every answer worked as easy as this stack would be even better! thanks – Spinstaz Sep 25 '22 at 12:54
  • I add `Install-Package Microsoft.WindowsAPICodePack-Shell` in PowerShell and it doesn't work. I have to click manually in VS. Do you know why is that? – Ooker Dec 05 '22 at 13:14
69

Here is a pure C# version, nuget-free, that should work with all versions of .NET (including .NET Core, .NET 5, WPF, Winforms, etc.) and uses Windows Vista (and higher) IFileDialog interface with the FOS_PICKFOLDERS options so it has the nice folder picker Windows standard UI.

Update 2023/3/17: the class now support multiple selection.

I have also added WPF's Window type support but this is optional, the WPF-marked lines can just be removed.

usage:

var dlg = new FolderPicker();
dlg.InputPath = @"c:\windows\system32";
if (dlg.ShowDialog() == true)
{
    MessageBox.Show(dlg.ResultPath);
}

code:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows;
using System.Windows.Interop;

public class FolderPicker
{
    private readonly List<string> _resultPaths = new List<string>();
    private readonly List<string> _resultNames = new List<string>();

    public IReadOnlyList<string> ResultPaths => _resultPaths;
    public IReadOnlyList<string> ResultNames => _resultNames;
    public string ResultPath => ResultPaths.FirstOrDefault();
    public string ResultName => ResultNames.FirstOrDefault();
    public virtual string InputPath { get; set; }
    public virtual bool ForceFileSystem { get; set; }
    public virtual bool Multiselect { get; set; }
    public virtual string Title { get; set; }
    public virtual string OkButtonLabel { get; set; }
    public virtual string FileNameLabel { get; set; }

    protected virtual int SetOptions(int options)
    {
        if (ForceFileSystem)
        {
            options |= (int)FOS.FOS_FORCEFILESYSTEM;
        }

        if (Multiselect)
        {
            options |= (int)FOS.FOS_ALLOWMULTISELECT;
        }
        return options;
    }

    // for WPF support
    public bool? ShowDialog(Window owner = null, bool throwOnError = false)
    {
        owner = owner ?? Application.Current?.MainWindow;
        return ShowDialog(owner != null ? new WindowInteropHelper(owner).Handle : IntPtr.Zero, throwOnError);
    }

    // for all .NET
    public virtual bool? ShowDialog(IntPtr owner, bool throwOnError = false)
    {
        var dialog = (IFileOpenDialog)new FileOpenDialog();
        if (!string.IsNullOrEmpty(InputPath))
        {
            if (CheckHr(SHCreateItemFromParsingName(InputPath, null, typeof(IShellItem).GUID, out var item), throwOnError) != 0)
                return null;

            dialog.SetFolder(item);
        }

        var options = FOS.FOS_PICKFOLDERS;
        options = (FOS)SetOptions((int)options);
        dialog.SetOptions(options);

        if (Title != null)
        {
            dialog.SetTitle(Title);
        }

        if (OkButtonLabel != null)
        {
            dialog.SetOkButtonLabel(OkButtonLabel);
        }

        if (FileNameLabel != null)
        {
            dialog.SetFileName(FileNameLabel);
        }

        if (owner == IntPtr.Zero)
        {
            owner = Process.GetCurrentProcess().MainWindowHandle;
            if (owner == IntPtr.Zero)
            {
                owner = GetDesktopWindow();
            }
        }

        var hr = dialog.Show(owner);
        if (hr == ERROR_CANCELLED)
            return null;

        if (CheckHr(hr, throwOnError) != 0)
            return null;

        if (CheckHr(dialog.GetResults(out var items), throwOnError) != 0)
            return null;

        items.GetCount(out var count);
        for (var i = 0; i < count; i++)
        {
            items.GetItemAt(i, out var item);
            CheckHr(item.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out var path), throwOnError);
            CheckHr(item.GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEEDITING, out var name), throwOnError);
            if (path != null || name != null)
            {
                _resultPaths.Add(path);
                _resultNames.Add(name);
            }
        }
        return true;
    }

    private static int CheckHr(int hr, bool throwOnError)
    {
        if (hr != 0 && throwOnError) Marshal.ThrowExceptionForHR(hr);
        return hr;
    }

    [DllImport("shell32")]
    private static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);

    [DllImport("user32")]
    private static extern IntPtr GetDesktopWindow();

#pragma warning disable IDE1006 // Naming Styles
    private const int ERROR_CANCELLED = unchecked((int)0x800704C7);
#pragma warning restore IDE1006 // Naming Styles

    [ComImport, Guid("DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7")] // CLSID_FileOpenDialog
    private class FileOpenDialog { }

    [ComImport, Guid("d57c7288-d4ad-4768-be02-9d969532d960"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IFileOpenDialog
    {
        [PreserveSig] int Show(IntPtr parent); // IModalWindow
        [PreserveSig] int SetFileTypes();  // not fully defined
        [PreserveSig] int SetFileTypeIndex(int iFileType);
        [PreserveSig] int GetFileTypeIndex(out int piFileType);
        [PreserveSig] int Advise(); // not fully defined
        [PreserveSig] int Unadvise();
        [PreserveSig] int SetOptions(FOS fos);
        [PreserveSig] int GetOptions(out FOS pfos);
        [PreserveSig] int SetDefaultFolder(IShellItem psi);
        [PreserveSig] int SetFolder(IShellItem psi);
        [PreserveSig] int GetFolder(out IShellItem ppsi);
        [PreserveSig] int GetCurrentSelection(out IShellItem ppsi);
        [PreserveSig] int SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName);
        [PreserveSig] int GetFileName([MarshalAs(UnmanagedType.LPWStr)] out string pszName);
        [PreserveSig] int SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle);
        [PreserveSig] int SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText);
        [PreserveSig] int SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel);
        [PreserveSig] int GetResult(out IShellItem ppsi);
        [PreserveSig] int AddPlace(IShellItem psi, int alignment);
        [PreserveSig] int SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension);
        [PreserveSig] int Close(int hr);
        [PreserveSig] int SetClientGuid();  // not fully defined
        [PreserveSig] int ClearClientData();
        [PreserveSig] int SetFilter([MarshalAs(UnmanagedType.IUnknown)] object pFilter);
        [PreserveSig] int GetResults(out IShellItemArray ppenum);
        [PreserveSig] int GetSelectedItems([MarshalAs(UnmanagedType.IUnknown)] out object ppsai);
    }

    [ComImport, Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IShellItem
    {
        [PreserveSig] int BindToHandler(); // not fully defined
        [PreserveSig] int GetParent(); // not fully defined
        [PreserveSig] int GetDisplayName(SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
        [PreserveSig] int GetAttributes();  // not fully defined
        [PreserveSig] int Compare();  // not fully defined
    }

    [ComImport, Guid("b63ea76d-1f85-456f-a19c-48159efa858b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IShellItemArray
    {
        [PreserveSig] int BindToHandler();  // not fully defined
        [PreserveSig] int GetPropertyStore();  // not fully defined
        [PreserveSig] int GetPropertyDescriptionList();  // not fully defined
        [PreserveSig] int GetAttributes();  // not fully defined
        [PreserveSig] int GetCount(out int pdwNumItems);
        [PreserveSig] int GetItemAt(int dwIndex, out IShellItem ppsi);
        [PreserveSig] int EnumItems();  // not fully defined
    }

#pragma warning disable CA1712 // Do not prefix enum values with type name
    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_OVERWRITEPROMPT = 0x2,
        FOS_STRICTFILETYPES = 0x4,
        FOS_NOCHANGEDIR = 0x8,
        FOS_PICKFOLDERS = 0x20,
        FOS_FORCEFILESYSTEM = 0x40,
        FOS_ALLNONSTORAGEITEMS = 0x80,
        FOS_NOVALIDATE = 0x100,
        FOS_ALLOWMULTISELECT = 0x200,
        FOS_PATHMUSTEXIST = 0x800,
        FOS_FILEMUSTEXIST = 0x1000,
        FOS_CREATEPROMPT = 0x2000,
        FOS_SHAREAWARE = 0x4000,
        FOS_NOREADONLYRETURN = 0x8000,
        FOS_NOTESTFILECREATE = 0x10000,
        FOS_HIDEMRUPLACES = 0x20000,
        FOS_HIDEPINNEDPLACES = 0x40000,
        FOS_NODEREFERENCELINKS = 0x100000,
        FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
        FOS_DONTADDTORECENT = 0x2000000,
        FOS_FORCESHOWHIDDEN = 0x10000000,
        FOS_DEFAULTNOMINIMODE = 0x20000000,
        FOS_FORCEPREVIEWPANEON = 0x40000000,
        FOS_SUPPORTSTREAMABLEITEMS = unchecked((int)0x80000000)
    }
#pragma warning restore CA1712 // Do not prefix enum values with type name
}

result:

enter image description here

Community
  • 1
  • 1
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • Hi, I am presently trying to get the above to work in Visual Studio, C# 2015, .Net v4.8.04084 under Windows 10 Pro Build 21H1 OS Build 19043.1055. This line: if (CheckHr(SHCreateItemFromParsingName(InputPath, null, typeof(IShellItem).GUID, out var item), throwOnError) != 0) return null; for example is returning CS1003 C# Syntax error, ',' expected, any help would be appreciated, getting good in c# but - not this good yet.. – FalloutBoy Jun 15 '21 at 05:22
  • @FalloutBoy - If you're using an old C# version, replace `var` by the out variable type (for example `IShellItem` in this case) or even declare it outside the call, not inline https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#out-variables – Simon Mourier Jun 15 '21 at 05:28
  • Thanks Simon, I eventually got this working after reading your comments here, while your code does indeed run under this version if you take out the WPF parts it does require some localization of variables to the subroutines - I think that and the later c# syntax is what had me flummoxed but it's all good now. – FalloutBoy Jun 16 '21 at 07:52
  • 9
    Clearly the best answer! – Insert Clever Username Jul 24 '21 at 08:43
  • 4
    This is outstanding! Thank you! – gurrenm3 Nov 27 '21 at 14:57
  • Thanks! I removed the WPF-marked lines and then had a CS7036 error. Resolved by changing the call from `if (dlg.ShowDialog() == true)` to `if (dlg.ShowDialog(IntPtr.Zero) == true)`. I'm sure there's a more elegant fix that someone will share. – LesFerch Dec 10 '21 at 03:21
  • 3
    @LesFerch, it should be something like `if (dlg.ShowDialog(yourForm.Handle) == true)` or `if (dlg.ShowDialog(someControl.Handle) == true)`, otherwise a user may focus the one of forms/windows (other one that showed the browse dialog) – Maris B. Jan 12 '22 at 14:29
  • 1
    The code heped me with my C++ implementation of the same idea – Nick Deguillaume Sep 06 '22 at 11:29
  • This ALMOST does what I want. I'd like to be able to select folders (which it supports), but I'd also like to be able to select files, specifically zip files and perhaps other filetypes. I've played with FOS options without much luck. It appears that setting FOS.FOS_PICKFOLDERS hides files, but you can't select folders unless it is set. Is there a way to choose both files and folders? – d ei Nov 24 '22 at 01:54
  • @dei - not to my knowledge – Simon Mourier Nov 24 '22 at 06:59
  • I've used this successfully for a single folder selection. Can it be modified so the user can select multiple folders using Ctrl or Shift? – LesFerch Mar 17 '23 at 17:38
  • @LesFerch - good remark, I've added a `Multiselect` flag and you can read the list using `ResultPaths` or `ResultNames`. – Simon Mourier Mar 17 '23 at 18:30
  • 1
    Just incredible! Did you have this code ready to go or did you actually make those enhancements in 10 minutes? If the latter, your Kung Fu is most impressive. It took me far longer to integrate and test it. BTW, it works perfectly! Thank you! – LesFerch Mar 17 '23 at 19:42
  • @LesFerch - I just made from your remarks (it never crossed my mind before, I wasn't sure it was possible) it but I'm quite familiar to these technologies, just had to tie the bits together :-) – Simon Mourier Mar 17 '23 at 21:45
  • 1
    So there's sauce, and then there's awesome sauce. This is the latter. Well done, my dear boy. Very well done indeed! The most elegant solution I have seen to date. – stigzler Apr 24 '23 at 18:36
63

There is a hackish solution using OpenFileDialog where ValidateNames and CheckFileExists are both set to false and FileName is given a mock value to indicate that a directory is selected.

I say hack because it is confusing to users about how to select a folder. They need to be in the desired folder and then just press Open while file name says "Folder Selection."

C# Folder selection dialog

This is based on Select file or folder from the same dialog by Denis Stankovski.

OpenFileDialog folderBrowser = new OpenFileDialog();
// Set validate names and check file exists to false otherwise windows will
// not let you select "Folder Selection."
folderBrowser.ValidateNames = false;
folderBrowser.CheckFileExists = false;
folderBrowser.CheckPathExists = true;
// Always default to Folder Selection.
folderBrowser.FileName = "Folder Selection.";
if (folderBrowser.ShowDialog() == DialogResult.OK)
{
    string folderPath = Path.GetDirectoryName(folderBrowser.FileName);
    // ...
}
Daniel Ballinger
  • 13,187
  • 11
  • 69
  • 96
  • I see, yes I have gotten it working. One annoying thing is that `Folder Selection.` will be tacked onto the end of the filename like so: `C:\Folder Selection.` I guess you could always remove those characters from the string. Still looks better than the FolderBrowserDialog – ComradeJoecool May 10 '18 at 00:34
  • 1
    This doesn't work for me. It won't allow me to select folders. It just opens them. – Lokiare Aug 10 '18 at 17:52
  • 2
    @Lokiare That is what I meant when I said it was a hack. See the instructions from the second paragraph. – Daniel Ballinger Aug 11 '18 at 01:46
  • 2
    @ComradeJoecool you dont have to manually remove that manually. thats what the last line in the code is for: string folderPath = Path.GetDirectoryName(folderBrowser.FileName); – Heriberto Lugo Feb 24 '19 at 05:18
  • 2
    Oh! there is a problem with this method: if user press the **Up** or **Back** buttons when browsing the folders, the main `Open` button of the dialog does not work as expected! it cause you jump back to prev folder! but it works when you just double click folders to select them or select some files inside each folder (if there is any file you can choose) – S.Serpooshan Jun 18 '19 at 06:43
  • This could be useful: folderBrowser.Title = "Select Directory"; folderBrowser.InitialDirectory = iInitialDirectory; – Roberto Mutti Jul 04 '23 at 10:30
13

Strange that so much answers/votes, but no one add the following code as an answer:

using (var opnDlg = new OpenFileDialog()) //ANY dialog
{ 
    //opnDlg.Filter = "Png Files (*.png)|*.png";
    //opnDlg.Filter = "Excel Files (*.xls, *.xlsx)|*.xls;*.xlsx|CSV Files (*.csv)|*.csv"

    if (opnDlg.ShowDialog() == DialogResult.OK)
    {
        //opnDlg.SelectedPath -- your result
    }
}
Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101
  • 12
    Is there any difference between your answer and @Ionică Bizău [Answer](https://stackoverflow.com/questions/11624298/how-to-use-openfiledialog-to-select-a-folder/11624322#11624322)? – Chetan Mehra Jan 29 '18 at 07:37
  • 2
    Logic is the same, but my answer is much shorter and you no need to create extra variable for DialogResult. – Andrew_STOP_RU_WAR_IN_UA Jan 30 '18 at 21:23
  • 10
    As already mentioned, there are some big problems with this method: this is an awful tree view dialog! you can't copy-paste a path in to it, you have to drill one by one from root folder and there are no favorites panel! – S.Serpooshan Jul 21 '19 at 11:24
  • @S.Serpooshan i'ts doesnt matter. This is just a sample of use of ANY dialog. You can use any other dialog if you want. :) – Andrew_STOP_RU_WAR_IN_UA Jul 21 '19 at 12:27
  • 4
    @Andrew: Re.your Comment reply to "S.Serpooshan": Yes, actually it *does* matter. Per "Michael Paulukonis"'s Comment on "Apr 28 '15 at 15:09" (~1.5 yrs prior to your Answer) to "Ionică Bizău"'s Answer: "The question is *specifically* about using the *OpenFileDialog (OFD)* to select a folder, not the FolderBrowserDialog (FBD). I concur that the FBD is awful from a user standpoint." (emphasis added). Also, "Joe"'s Answer on "Jan 6 '17 at 18:03" (~2.5 yrs prior to your Comment) already provided *exactly* what the OP was asking (i.e. folder selection w/ all the features of OFD not in FBD). – Tom Nov 25 '20 at 17:15
  • Yes how strange that a file dialog and a folder dialog are not the same thing. – Derf Skren Mar 10 '21 at 00:29
  • Don´t get this answer, obviously not working.. – Dr.Escher Mar 25 '22 at 10:11
12

Sounds to me like you're just after the FolderBrowserDialog.

Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • 14
    I guess this is getting downvoted b/c (as mistika already pointed out) the FolderBrowserDialog has horrible usability and OP explicitly wanted to use the OpenFileDialog. – mbx Dec 19 '16 at 14:39
  • 3
    @mbx Perhaps. To be fair, the OP doesn't say "I can't use anything but the OpenFileDialog". When I originally answered this (over 4 and a half years ago...), the assumption was that the OP just didn't know how to let a user open a folder. I didn't actually return to this question after posting this answer so I have not seen any of the discussion around usability - nor did I consider it when answering. – Simon Whitehead Dec 20 '16 at 09:30
9

Here is another solution, that has all the source available in a single, simple ZIP file.

It presents the OpenFileDialog with additional windows flags that makes it work like the Windows 7+ Folder Selection dialog.

Per the website, it is public domain: "There’s no license as such as you are free to take and do with the code what you will."

Archive.org links:

Ben Keene
  • 459
  • 4
  • 7
  • 1
    Work perfectly!. Also you can make it select multiple folder by adding this line in "FolderSelectDialog.cs" : public string[] FileNames { get { return ofd.FileNames; } } and change ofd.Multiselect = true; in the constructor – Maxter Feb 22 '19 at 16:52
  • 1
    Unfortunately, this does not work if `Application.VisualStyleState` is disabled: `Application.VisualStyleState = System.Windows.Forms.VisualStyles.VisualStyleState.NoneEnabled;`. You will run into [this](https://stackoverflow.com/questions/29929862/exception-from-hresult-0x80040111-class-e-classnotavailable)... – Rotax Feb 03 '21 at 14:16
  • Unfortunately, I haven't had a chance to research this (and won't for some time) but from here: https://medium.com/lextm/openfiledialog-crashes-with-comexception-0x80040111-f51e18d1ab89 They recommend setting FileDialog.AutoUpgradeEnabled to false – Ben Keene Feb 04 '21 at 18:28
9

Take a look at the Ookii Dialogs libraries which has an implementation of a folder browser dialog for Windows Forms and WPF respectively.

enter image description here

Ookii.Dialogs.WinForms

https://github.com/augustoproiete/ookii-dialogs-winforms


Ookii.Dialogs.Wpf

https://github.com/augustoproiete/ookii-dialogs-wpf

C. Augusto Proiete
  • 24,684
  • 2
  • 63
  • 91
  • good. note: Ookii.Dialogs requires Microsoft .NET Framework 4.5 or higher. (can't be used in WinXP) – S.Serpooshan Jun 18 '19 at 06:50
  • 8
    @S.Serpooshan -- Well I guess it won't work on my Windows 3.1 PC either, right? But seriously, in 2018, no one should be thinking about Windows XP anyway -- it's long dead. – rory.ap Aug 20 '19 at 11:41
  • @rory.ap actually, the main problem of this solution for me is that it doesn't show the files when browsing for folders. It is sometimes very useful to be able to see the files (e.g. images to be processed) when user wants to select the folder! – S.Serpooshan Aug 21 '19 at 11:19
  • 1
    Unfortunately, this does not work if `Application.VisualStyleState` is disabled: `Application.VisualStyleState = System.Windows.Forms.VisualStyles.VisualStyleState.NoneEnabled;`. You will run into [this](https://stackoverflow.com/questions/29929862/exception-from-hresult-0x80040111-class-e-classnotavailable)... – Rotax Feb 03 '21 at 11:50
  • @Rotax I'd be interested in understanding more about that - i.e. Why do you need to disable the `VisualStyleState` in the first place, and there's a valid use-case, perhaps investigate if a workaround is possible. Would you like to open an issue in the repo? https://github.com/augustoproiete/ookii-dialogs-winforms/issues – C. Augusto Proiete Feb 03 '21 at 16:08
  • 1
    @AugustoProiete Sure, the reason for disabling `VisualStyleState` is because it makes a e.g. winforms form with a lot of controls actually 'faster'. See my SO post [here](https://stackoverflow.com/questions/59909008/for-winforms-applications-calling-filedialog-on-win10-the-context-menu-is-empty). I am afraid the issue is deep and will be unresolved for a long time (if ever)... My workaround is [FolderBrowserDialogEx](https://stackoverflow.com/questions/576741/customising-the-browse-for-folder-dialog-to-show-the-path) - and I hope to switch to WPF soon. – Rotax Feb 12 '21 at 10:57
1

Im new to C# and came across this thread just now.

This might be of interest to those that are new to the language as well.

Change design of FolderBrowserDialog

0

The answer given by Simon Mourier would be the best answer considering the OP question. It does not involve NuGET package so there will not be any dependency issue in the future for selecting folder method.

If you encountered error related to "...is not available in C# 7.3", just add <LangVersion>8.0</LangVersion> to your .csproj (testing with Visual Studio does not produce any error when build and run)

If you can't change the project language then just replace owner ??= Application.Current.MainWindow with

owner = owner ?? Application.Current.MainWindow

Catple
  • 1
  • 2
0

This is how I use the folder browser dialog in Small Visual Basic. This code solves the non-selected initial folder issue, and also selects the folder from the clipboard or the registry (if any), and if the folder is deleted it goes up throw parents until selecting an existing folder. This makes using the dialog very comfortable. Note that I am sending 4 tabs because I show the Create new folder button, but if you hide it, use two tabs only.

 Public Shared Function OpenFolderDialog(initialFolder As String) As String
                Dim folder = GeIinitialFolder(initialFolder)
                If folder = "" Then folder = GeIinitialFolder(System.Windows.Clipboard.GetText())
                If folder = "" Then folder = GeIinitialFolder(GetSetting("sVB", "OpenFolder", "LastFolder", ""))

                Dim th As New Threading.Thread(
                    Sub()
                        Threading.Thread.Sleep(300)
                        System.Windows.Forms.SendKeys.SendWait("{TAB}{TAB}{TAB}{TAB}{RIGHT}")
                    End Sub)
                th.Start()


                Try
                    Dim dlg As New System.Windows.Forms.FolderBrowserDialog With {
                        .Description = "Select a folder:",
                        .SelectedPath = folder
                    }

                    If dlg.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
                        SaveSetting("sVB", "OpenFolder", "LastFolder", dlg.SelectedPath)
                        OpenFolderDialog = dlg.SelectedPath
                    End If

                Catch ex As Exception
                    MsgBox(ex.Message)
                End Try
    End Function

    Private Shared Function GeIinitialFolder(folder As String) As String
        Try
            If folder <> "" Then
                If IO.File.Exists(folder) Then
                    folder = Path.GetDirectoryName(folder)
                Else
                    Do
                        If Directory.GetDirectoryRoot(folder) = folder OrElse Directory.Exists(folder) Then
                            Exit Do
                        End If
                        folder = Path.GetDirectoryName(folder)
                    Loop
                End If
            End If

        Catch
            folder = ""
        End Try

        Return folder
    End Function
-6

this should be the most obvious and straight forward way

using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
{

   System.Windows.Forms.DialogResult result = dialog.ShowDialog();

   if(result == System.Windows.Forms.DialogResult.OK)
   {
      selectedFolder = dialog.SelectedPath;
   }

}
AHM
  • 15
  • 3
  • 9
    `FolderBrowserDialog` has already been offered here multiple times, and is the wrong answer. It's an outdated and very non-user-friendly interface. It uses [`SHBrowseForFolder`](https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shbrowseforfoldera) underneath, and even the docs state *"For Windows Vista or later, it is recommended that you use `IFileDialog` with the `FOS_PICKFOLDERS` option rather than the `SHBrowseForFolder` function. This uses the Open Files dialog in pick folders mode and is the preferred implementation."* – Herohtar Nov 22 '19 at 20:17