We've all used
FolderBrowserDialog and its precursor
SHBrowseForFolder. While these common controls are very useful in stock form, they never quite seem to do exactly what you want - there's always some UI artifact that you really don't want. And, like many things in .NET, the managed API seems to be a thin wrapper around the unmanaged API, and the managed API therefore inherits all the quirks.
I had a few gripes about
- The stock "Browse For Folder" dialog title... I want to say something more informative.
- There's no option for a path edit box... it's in
SHBrowseForFolder but disappeared in
In setting out to solve the issues, I started in the usual way: search the Web for code samples! I found two particularly useful samples:
Neither of which was the exact solution I sought, but both provided invaluable starting points.
XBrowseForFolder had many of the features I wanted... but it's in C++. PInvoke's
SHBrowseForFolder C# sample code provided a glimpse into what's possible in managed code, but is just a snippet. I encourage you to explore both links above as they can provide details that this sample intentionally omits.
Using the Code
XBrowseForFolder does a great job explaining the techniques for using
SHBrowseForFolder, so I won't rehash that here. The one semi-messy part of doing it in .NET is the interaction between managed and unmanaged code, specifically connecting to
SHBrowseForFolder's callback function. This requires Marshaling and a class - herein named
InitData - to pass data from the main function to the callback. I originally tried to pass the class object itself to the callback but that would hang, thus a helper class was necessary.
The attached sample code contains a
FolderBrowserDialogEx classlib and a WinForms app that demos it. The classlib's implementation is in FolderBrowserDialogEx.cs; the attendant P/Invoke code is in Win32.cs. The demo app is pretty much boilerplate. The main form,
Form1, is designed to look and behave like the demo UI in
FolderBrowserDialogEx interface mimics that of
FolderBrowserDialogEx cfbd = new FolderBrowserDialogEx();
cfbd.SelectedPath = @"c:\";
cfbd.ShowNewFolderButton = true;
cfbd.RootFolder = Environment.SpecialFolder.Desktop;
cfbd.Title = "Your custom title";
cfbd.ShowEditbox = true;
cfbd.StartPosition = FormStartPosition.CenterScreen;
if (cfbd.ShowDialog(this) == DialogResult.OK)
Points of Interest
SHBrowseForFolder took a surprising number of P/Invoke APIs. I found that to do a proper job, we must have a good grounding in the pre-.NET world. I found it interesting that the stock
FolderBrowserDialog doesn't offer the path editbox but it does offer the "Create New Folder" button. Seems to me that users would often enough want to type or paste a path so as to warrant the inclusion of the editbox.
I was interested and annoyed to find that
BIF_NEWDIALOGSTYLE makes it really hard to override the stock behavior. In particular, when
BIF_NEWDIALOGSTYLE is applied, you absolutely cannot reposition the editbox... some code fights you and puts the editbox where it wants even when you try to put it where you want.
XBrowseForFolder to be a blast from the past. It hasn't been that long since unmanaged C++ was my primary environment, but a quick tour through this older code really made me appreciate how elegant C#/WinForms is compared to C++/MFC.