How do I use OpenFileDialog to select a folder?
Asked Answered
C

13

451

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?

Countess answered 24/7, 2012 at 4:43 Comment(10)
If you open the project file with editor, you will notice some additional properties at the bottom: <VCIncludePath ...>, <Win32Resource ...> and <Target Name="BeforeBuild"...>. 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.Stallfeed
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 dialogCanto
Possible duplicate of How do you configure an OpenFileDialog to select folders?Vasques
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.Fisc
@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 falseLurlenelurline
@Lurlenelurline I've converted my comment to an answer. I tried it several times and didn't have a "file not found" issue. Are you reusing the same OpenFileDialog instance?Canto
@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)Lurlenelurline
I think this nuget package is a good choice BetterFolderBrowserMendelson
I would strongly suggest changing the selected answer Simon Mourier's answer 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.Sessler
I shared another working answer here: https://mcmap.net/q/81542/-how-add-multiselect-to-this-custom-file-dialogFootrope
W
471

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);
}
Workable answered 6/1, 2017 at 18:3 Comment(14)
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.Odisodium
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.Whoso
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.Scholarship
If you use this with VS2017 it restyles your main window.Soble
nice find. Not sure why Microsoft doesn't include this in their main VS libraires.Idelson
Note for FolderBrowserDialog users: multiple simultaneous instance usage of it can create problems. This CommonOpenFileDialog is better.Upturn
Microsoft seems to have republished it as WindowsAPICodePack-ShellBernard
Just wrap in using statement, as it has inherited IDisposableCharmainecharmane
@Soble this fixes the resizing problem #42975785Yonina
Sadly when i use this it fails to load the assembly, despite it being included with my build.Poncho
As others have said, this should be the accepted answer, as it works perfectly and avoids using the horrible/unusable FolderBrowserDialog.Dehiscence
The NuGet package linked wasn't working for me in .NET 5 as it failed to load the assembly. Using Microsoft-WindowsAPICodePack-Shell did work though.Kentkenta
If every answer worked as easy as this stack would be even better! thanksGame
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?Austreng
M
523

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

Monetary answered 24/7, 2012 at 4:46 Comment(9)
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.Stallfeed
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.Dundalk
Alternatively to this dialog with broken UI, use a CommonOpenFileDialog: new CommonOpenFileDialog { IsFolderPicker = true }.Payee
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.Corie
FolderBrowserDialog has one big flaw besides everything else that the other users said. It does not remember the last selected path!Indoxyl
Note that FolderBrowserDialog uses SHBrowseForFolder 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!Consubstantiate
With .NET Core 3 FolderBrowserDialog will have the same UI as the one in WindowsAPICodePack. learn.microsoft.com/en-us/dotnet/core/porting/…Sculpt
Is there any way to get the save file dialog which is already opened ? like we do with forms Application.OpenFormsStarstarboard
@Consubstantiate 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.Sessler
W
471

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);
}
Workable answered 6/1, 2017 at 18:3 Comment(14)
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.Odisodium
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.Whoso
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.Scholarship
If you use this with VS2017 it restyles your main window.Soble
nice find. Not sure why Microsoft doesn't include this in their main VS libraires.Idelson
Note for FolderBrowserDialog users: multiple simultaneous instance usage of it can create problems. This CommonOpenFileDialog is better.Upturn
Microsoft seems to have republished it as WindowsAPICodePack-ShellBernard
Just wrap in using statement, as it has inherited IDisposableCharmainecharmane
@Soble this fixes the resizing problem #42975785Yonina
Sadly when i use this it fails to load the assembly, despite it being included with my build.Poncho
As others have said, this should be the accepted answer, as it works perfectly and avoids using the horrible/unusable FolderBrowserDialog.Dehiscence
The NuGet package linked wasn't working for me in .NET 5 as it failed to load the assembly. Using Microsoft-WindowsAPICodePack-Shell did work though.Kentkenta
If every answer worked as easy as this stack would be even better! thanksGame
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?Austreng
C
76

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

Colorist answered 13/2, 2021 at 16:12 Comment(15)
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..Ornamentation
@Ornamentation - 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 learn.microsoft.com/en-us/dotnet/csharp/whats-new/…Colorist
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.Ornamentation
Clearly the best answer!Bolter
This is outstanding! Thank you!Inapprehensive
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.Honk
@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)Ethelethelbert
The code heped me with my C++ implementation of the same ideaStanch
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?Babbittry
@dei - not to my knowledgeColorist
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?Honk
@Honk - good remark, I've added a Multiselect flag and you can read the list using ResultPaths or ResultNames.Colorist
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!Honk
@Honk - 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 :-)Colorist
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. 👏Waterscape
C
67

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);
    // ...
}
Canto answered 10/5, 2018 at 0:20 Comment(6)
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 FolderBrowserDialogLurlenelurline
This doesn't work for me. It won't allow me to select folders. It just opens them.Soble
@Soble That is what I meant when I said it was a hack. See the instructions from the second paragraph.Canto
@Lurlenelurline you dont have to manually remove that manually. thats what the last line in the code is for: string folderPath = Path.GetDirectoryName(folderBrowser.FileName);Actiniform
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)Nador
This could be useful: folderBrowser.Title = "Select Directory"; folderBrowser.InitialDirectory = iInitialDirectory;Quartic
E
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
    }
}
Ephesian answered 17/11, 2016 at 21:22 Comment(7)
Is there any difference between your answer and @Ionică Bizău Answer?Arnulfoarny
Logic is the same, but my answer is much shorter and you no need to create extra variable for DialogResult.Ephesian
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!Nador
@Nador i'ts doesnt matter. This is just a sample of use of ANY dialog. You can use any other dialog if you want. :)Ephesian
@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).Erupt
Yes how strange that a file dialog and a folder dialog are not the same thing.Empyreal
Don´t get this answer, obviously not working..Manley
T
10

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

Tate answered 24/7, 2012 at 4:45 Comment(2)
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.Phenacaine
@Phenacaine 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.Tate
B
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:

Blooper answered 23/8, 2018 at 18:20 Comment(4)
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 constructorGrandam
Unfortunately, this does not work if Application.VisualStyleState is disabled: Application.VisualStyleState = System.Windows.Forms.VisualStyles.VisualStyleState.NoneEnabled;. You will run into this...Monticule
Unfortunately, I haven't had a chance to research this (and won't for some time) but from here: medium.com/lextm/… They recommend setting FileDialog.AutoUpgradeEnabled to falseBlooper
Specifying owner will cause freezing when call ShowDialog(owner), tested on win10 and win7.Superiority
N
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

No answered 20/10, 2018 at 20:32 Comment(6)
good. note: Ookii.Dialogs requires Microsoft .NET Framework 4.5 or higher. (can't be used in WinXP)Nador
@Nador -- 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.Binnacle
@Binnacle 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!Nador
Unfortunately, this does not work if Application.VisualStyleState is disabled: Application.VisualStyleState = System.Windows.Forms.VisualStyles.VisualStyleState.NoneEnabled;. You will run into this...Monticule
@Monticule 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? github.com/augustoproiete/ookii-dialogs-winforms/issuesNo
@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. I am afraid the issue is deep and will be unresolved for a long time (if ever)... My workaround is FolderBrowserDialogEx - and I hope to switch to WPF soon.Monticule
F
2

Don't reject FolderBrowserDialog just yet. If you are on .NET Core (e.g. .NET 5 and higher; with <UseWindowsForms>true</UseWindowsForms>), there is the AutoUpgradeEnabled property (true by default), which controls whether the dialog is allowed to upgrade. When enabled, it will use the newer common dialog without needing any additional effort.

On .NET Framework, I know of no standardized solution.

Fibrinous answered 4/12, 2023 at 16:35 Comment(1)
This should be higher. Microsoft basicaly fixed their FolderBrowserDialog in the new .net versions. There is no longer any need for a nuget package or some custom classGrandam
T
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

Taub answered 23/9, 2022 at 8:2 Comment(0)
S
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

Schoenburg answered 7/9, 2022 at 3:31 Comment(0)
Q
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
Quincy answered 16/2, 2023 at 1:27 Comment(0)
I
-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;
   }

}
Ironsmith answered 22/9, 2019 at 17:40 Comment(1)
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 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."Consubstantiate

© 2022 - 2024 — McMap. All rights reserved.