How do you configure an OpenFileDialog to select folders?

Viewed 239445

In VS .NET, when you are selecting a folder for a project, a dialog that looks like an OpenFileDialog or SaveFileDialog is displayed, but is set up to accept only folders. Ever since I've seen this I've wanted to know how it's done. I am aware of the FolderBrowserDialog, but I've never really liked that dialog. It starts too small and doesn't let me take advantage of being able to type a path.

I'm almost certain by now there's not a way to do this from .NET, but I'm just as curious how you do it from unmanaged code as well. Short of completely reimplementing the dialog from scratch, how do you modify the dialog to have this behavior?

I'd also like to restate that I am aware of the FolderBrowserDialog but sometimes I don't like to use it, in addition to being genuinely curious how to configure a dialog in this manner. Telling me to just use the FolderBrowserDialog helps me maintain a consistent UI experience but doesn't satisfy my curiosity so it won't count as an answer.

It's not a Vista-specific thing either; I've been seeing this dialog since VS .NET 2003, so it is doable in Win2k and WinXP. This is less of a "I want to know the proper way to do this" question and more of a "I have been curious about this since I first wanted to do it in VS 2003" question. I understand that Vista's file dialog has an option to do this, but it's been working in XP so I know they did something to get it to work. Vista-specific answers are not answers, because Vista doesn't exist in the question context.

Update: I'm accepting Scott Wisniewski's answer because it comes with a working sample, but I think Serge deserves credit for pointing to the dialog customization (which is admittedly nasty from .NET but it does work) and Mark Ransom for figuring out that MS probably rolled a custom dialog for this task.

17 Answers

I have a dialog that I wrote called an OpenFileOrFolder dialog that allows you to open either a folder or a file.

If you set its AcceptFiles value to false, then it operates in only accept folder mode.

You can download the source from GitHub here

There is the Windows API Code Pack. It's got a lot of shell related stuff, including the CommonOpenFileDialog class (in the Microsoft.WindowsAPICodePack.Dialogs namespace). This is the perfect solution - the usual open dialog with only folders displayed.

Here is an example of how to use it:

CommonOpenFileDialog cofd = new CommonOpenFileDialog();
cofd.IsFolderPicker = true;
cofd.ShowDialog();

Unfortunately Microsoft no longer ships this package, but several people have unofficially uploaded binaries to NuGet. One example can be found here. This package is just the shell-specific stuff. Should you need it, the same user has several other packages which offer more functionality present in the original package.

You can use FolderBrowserDialogEx - a re-usable derivative of the built-in FolderBrowserDialog. This one allows you to type in a path, even a UNC path. You can also browse for computers or printers with it. Works just like the built-in FBD, but ... better.

(EDIT: I should have pointed out that this dialog can be set to select files or folders. )

Full Source code (one short C# module). Free. MS-Public license.

Code to use it:

var dlg1 = new Ionic.Utils.FolderBrowserDialogEx();
dlg1.Description = "Select a folder to extract to:";
dlg1.ShowNewFolderButton = true;
dlg1.ShowEditBox = true;
//dlg1.NewStyle = false;
dlg1.SelectedPath = txtExtractDirectory.Text;
dlg1.ShowFullPathInEditBox = true;
dlg1.RootFolder = System.Environment.SpecialFolder.MyComputer;

// Show the FolderBrowserDialog.
DialogResult result = dlg1.ShowDialog();
if (result == DialogResult.OK)
{
    txtExtractDirectory.Text = dlg1.SelectedPath;
}

Better to use the FolderBrowserDialog for that.

using (FolderBrowserDialog dlg = new FolderBrowserDialog())
{
    dlg.Description = "Select a folder";
    if (dlg.ShowDialog() == DialogResult.OK)
    {
        MessageBox.Show("You selected: " + dlg.SelectedPath);
    }
}

OK, let me try to connect the first dot ;-) Playing a little bit with Spy++ or Winspector shows that the Folder textbox in the VS Project Location is a customization of the standard dialog. It's not the same field as the filename textbox in a standard file dialog such as the one in Notepad.

From there on, I figure, VS hides the filename and filetype textboxes/comboboxes and uses a custom dialog template to add its own part in the bottom of the dialog.

EDIT: Here's an example of such customization and how to do it (in Win32. not .NET):

m_ofn is the OPENFILENAME struct that underlies the file dialog. Add these 2 lines:

  m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEDIALOG_IMPORTXLIFF);
  m_ofn.Flags |= OFN_ENABLETEMPLATE;

where IDD_FILEDIALOG_IMPORTXLIFF is a custom dialog template that will be added in the bottom of the dialog. See the part in red below. alt text
(source: apptranslator.com)

In this case, the customized part is only a label + an hyperlink but it could be any dialog. It could contain an OK button that would let us validate folder only selection.

But how we would get rid of some of the controls in the standard part of the dialog, I don't know.

More detail in this MSDN article.

Exact Audio Copy works this way on Windows XP. The standard file open dialog is shown, but the filename field contains the text "Filename will be ignored".

Just guessing here, but I suspect the string is injected into the combo box edit control every time a significant change is made to the dialog. As long as the field isn't blank, and the dialog flags are set to not check the existence of the file, the dialog can be closed normally.

Edit: this is much easier than I thought. Here's the code in C++/MFC, you can translate it to the environment of your choice.

CFileDialog dlg(true, NULL, "Filename will be ignored", OFN_HIDEREADONLY | OFN_NOVALIDATE | OFN_PATHMUSTEXIST | OFN_READONLY, NULL, this);
dlg.DoModal();

Edit 2: This should be the translation to C#, but I'm not fluent in C# so don't shoot me if it doesn't work.

OpenFileDialog openFileDialog1 = new OpenFileDialog();

openFileDialog1.FileName = "Filename will be ignored";
openFileDialog1.CheckPathExists = true;
openFileDialog1.ShowReadOnly = false;
openFileDialog1.ReadOnlyChecked = true;
openFileDialog1.CheckFileExists = false;
openFileDialog1.ValidateNames = false;

if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
    // openFileDialog1.FileName should contain the folder and a dummy filename
}

Edit 3: Finally looked at the actual dialog in question, in Visual Studio 2005 (I didn't have access to it earlier). It is not the standard file open dialog! If you inspect the windows in Spy++ and compare them to a standard file open, you'll see that the structure and class names don't match. When you look closely, you can also spot some differences between the contents of the dialogs. My conclusion is that Microsoft completely replaced the standard dialog in Visual Studio to give it this capability. My solution or something similar will be as close as you can get, unless you're willing to code your own from scratch.

You can subclass the file dialog and gain access to all its controls. Each has an identifier that can be used to obtain its window handle. You can then show and hide them, get messages from them about selection changes etc. etc. It all depends how much effort you want to take.

We did ours using WTL class support and customized the file dialog to include a custom places bar and plug-in COM views.

MSDN provides information on how to do this using Win32, this CodeProject article includes an example, and this CodeProject article provides a .NET example.

You can use code like this

  • The filter is hide files
  • The filename is hide first text

To advanced hide of textbox for filename you need to look at OpenFileDialogEx

The code:

{
    openFileDialog2.FileName = "\r";
    openFileDialog1.Filter = "folders|*.neverseenthisfile";
    openFileDialog1.CheckFileExists = false;
    openFileDialog1.CheckPathExists = false;
}

I assume you're on Vista using VS2008? In that case I think that the FOS_PICKFOLDERS option is being used when calling the Vista file dialog IFileDialog. I'm afraid that in .NET code this would involve plenty of gnarly P/Invoke interop code to get working.

Try this one from Codeproject (credit to Nitron):

I think it's the same dialog you're talking about - maybe it would help if you add a screenshot?

bool GetFolder(std::string& folderpath, const char* szCaption=NULL, HWND hOwner=NULL)
{
    bool retVal = false;

    // The BROWSEINFO struct tells the shell how it should display the dialog.
    BROWSEINFO bi;
    memset(&bi, 0, sizeof(bi));

    bi.ulFlags   = BIF_USENEWUI;
    bi.hwndOwner = hOwner;
    bi.lpszTitle = szCaption;

    // must call this if using BIF_USENEWUI
    ::OleInitialize(NULL);

    // Show the dialog and get the itemIDList for the selected folder.
    LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);

    if(pIDL != NULL)
    {
        // Create a buffer to store the path, then get the path.
        char buffer[_MAX_PATH] = {'\0'};
        if(::SHGetPathFromIDList(pIDL, buffer) != 0)
        {
            // Set the string value.
            folderpath = buffer;
            retVal = true;
        }       

        // free the item id list
        CoTaskMemFree(pIDL);
    }

    ::OleUninitialize();

    return retVal;
}

You can use code like this

The filter is empty string. The filename is AnyName but not blank

        openFileDialog.FileName = "AnyFile";
        openFileDialog.Filter = string.Empty;
        openFileDialog.CheckFileExists = false;
        openFileDialog.CheckPathExists = false;

I know the question was on configuration of OpenFileDialog but seeing that Google brought me here i may as well point out that if you are ONLY looking for folders you should be using a FolderBrowserDialog Instead as answered by another SO question below

How to specify path using open file dialog in vb.net?

Related