Unlike Windows Forms, the WPF OpenFileDialog and SaveFileDialog work differently, and catching messages or grabbing handles before they display does not work in this scenario. So, the trick used for their Windows Forms counterparts to extend them cannot be applied for WPF, and I had to go for a very different alternative. I used the free Red Gate Reflector[^] to get the relevant code from PresentationFramework.dll and recreate the existing functionality in my own namespace. While trying to reverse engineer the OpenFileDialog and SaveFileDialog, I was forced to go two levels deep to the FileDialog class because these classes override an abstract method called RunFileDialog with a parameter of the OPENFILENAME_I type that is internal to the PresentationFramework assembly only.

So, I ended up extracting a few more additional helper types used by my own FileDialog type, the base class for the new OpenFileDialog and SaveFileDialog. Since I grabbed all the code from the version 3.5 of the assembly, be advised that some new features introduced by .NET 4.0 into the Microsoft.Win32.FileDialog class like CustomPlaces [^] will not be available. Everything is packaged into the WpfCustomFileDialog assembly under the same namespace.

To make things more interesting and to give you the feel of a real world application, I have used the OpenFileDialog in conjunction with a media viewer based on Lee Brimelow's code[^], and SaveFileDialog with a media encoder settings window that is merely a redesign of Armoghan Asif's work[^]. In order for the latter to work properly, you would have to download and install the now obsoleted Windows Media Encoder 9[^] if you want to have full functionality, and obviously the runtime for .NET 3.5[^] or later. However, the utilization of the media component or encoder will not be the focus of this article.

The new OpenFileDialog and SaveFileDialog I've created can only manipulate old style window handles, but existing WPF controls don't have one. That made the System.Windows.Window a good candidate for a WPF child since it seems to be the only one to have an easily accessible handle represented as an IntPtr type. There is a caveat, as you’ll see in my code snippets below because extra code is needed to deal with different runtime versions.

Fortunately, there is also a way to assign a Windows handle to a UserControl that does not depend on the runtime version and that makes it the preferred design in my opinion. I'll elaborate more about it later in this article. In order to show the similarities of the two approaches, I've duplicated the same functionality on two tabs, one using a Window and the other a UserControl.

My new dialog type has to be aware of the window that will become one of its children and vice versa, so they can update their appearance when needed. To have some strong type checking when developing, I've created two interfaces to make it easier to enforce type safety. The old FileDialog class has become the new FileDialogExt, that looks like below:

As you might have guessed, T is the child type that will implement the IWindowExt interface. It makes sense to try to abstract the common behavior that the UserControl and Window types are sharing and use the inheritance and generics constraints to enforce it.

When using a Window, the above anonymous delegate captures the HwndSource that will provide the handle and the message loop for it. If using a UserControl, the HwndSource is programmatically created and is associated with it, so we can have the Windows handle to work with. Finally, the CustomPostCreation will do the final resizing to make it look like a real child.

As you might expect, mixing WPF with Win32 comes with issues. This is the main reason why we needed the HwndSourceHook delegate from the child window or the User Control. It provided not only a Win32 handle, but also a message loop to be used as a way to fix it:

You will need one of the latest versions of Windows and .NET 4.0 to use Microsoft.Win32.FileDialog.CustomPlaces[^]. Since this is not included because I’ve based my code on the older .NET 3.5, I included my own implementation that can handle older versions too. The code for this feature is similar with the what I’ve done in my previous article Extend OpenFileDialog and SaveFileDialog the easy way[^]. The main difference is the fact that instead of using extension methods, I use plain data members in the FileDialogExt class. The overridden FileDialog.RunDialog calls the methods described below:

You should only care about calling SetPlaces which takes an argument as an array of up to five objects that can be numbers representing Windows special folders or strings as regular folders. For your convenience, I’ve included the Places helper enumeration for predefined special folders.

Add the WpfCustomFileDialog project to your solution and reference it in your project. If you don't like this way, as other alternatives, you could just reference this DLL or drop the code into your own project.

Create the child window or the user control, and implement the IWindowExt interface.

Set up the properties and events exposed by IFileDlgExt in your child window or externally.

Create the dialog using its constructor and the child window type as a generic parameter.

Unfortunately, WPF window inheritance is not supported by the Visual Studio designer, and you've got some manual typing to do[^] in the XAML file. My inherited class has to set the xmlns:src attribute, and the SelectWindow.xaml file becomes:

Be advised that ParentDlg is null in the constructor and it is initialized for the subsequent events only.

I have included solutions for Visual Studio 2008 (v9) and 2010 (v10). If you choose not to install Windows Media Encoder 9, you will still have some limited runtime functionality but the VS 2010 solution might not build. To fix it, you would have to add the existing Interop.WMEncoderLib.dll assembly as a reference to the VideoManager project.
If Visual Studio starts complaining about weird errors while building or running, close the solution and delete all the bin and obj folders before trying again.

I have tested this project only on Windows XP SP3 32 bit and .NET 3.5 and 4.0. You might think that everything was pretty straightforward, but I can tell you that the development involved lots of trial and error phases or compromises. If you find ways to improve it like getting the relevant code from the latest version of the PresentationFramework.dll assembly, or make bug fixes, let me know and I'll try to have them in a future update.

If you are interested in Video encoding, you should probably consider replacing the existing deprecated Windows Media Encoder 9 encoder with the latest Expression Encoder[^]. While the code shown in the article is only C#, for the VB.NET folks, I have included the equivalent Visual Basic .NET solutions for Visual Studio 2008 and 2010 in the download source file.

Version 1.0 The original

Version 1.1 improves the child layout, suppresses the Window flash, and most importantly, adds support for the UserControl to be used as an extension

Version 1.2 adds my own CustomPlaces and fixes some incompatibilities with .NET 4.0

Version 1.3 adds VS 2013 project style, an access warning for CustomPlaces and moved the latest source code on codeplex.

so I have the extended dialog created and working. I have my "openFileDialog.Multiselect= true" but when I try to multiselect it throws the "illegal characters in path" exception and I don't know why. this happens as soon as I click the second file. it shows the exception on the .showDialog() method. does anyone have an example of multiselect working?

When i used this code in Win7 it still shows the old XP open dialog. I need a solution to change the open Dialog theme for Win 7. what change should I make in your code.? It will be very helpful if yu give a solution.

I have a WpfCustomFileDialog displaying a control in the right hand position and it looks nice - the original dialog width (571px) is extended by the width of the control (260px) to the total width of 831px. On one computer though (same as others: Windows 7 64-bit, .NET 4) the width of the dialog is not increased when adding a control and the total dialog width is 571px resulting in the original content being squashed, because the right hand panel takes almost half of the available space. The original open file dialog content is too narrow to display file name TextBox and a few other controls.
Has anyone come across this behavior?

EDIT:
OK, I managed to find a workaround:
For some strange reason on some machines the Dialog kept being reset to its original dimensions after it was set in CustomPostCreation(). To solve that I store the final Dialog size at the end of CustomPostCreation() and later in HookProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) if the Dialog dimensions are smaller than expected, I set them back to the correct size.

There was another problem on some machines: the buttons usually displayed to the right of the folder selection combo box were not drawn at all. I found out that there is a child control with ID 0x460. When I handle it the same way as DefaultView 0x461, everything works. If anyone knows what this control is, please tell me.

Hi,
I'm trying to set the InitialDirectory of my custom open file dialog to some permanent directory (e.g. "C:\\").
The behavior I require is that each time the user reopens the dialog the permanent directory will open (e.g. "C:\\") as the initial directory.
I get a very weird behavior where the property works when running my application locally but not when running from a ClickOnce network deployment.
When I run it from the network deployment the dialog "remembers" the initial directory from the last time the dialog was used instead of opening "C:\\".
I could not find any information about this so I'm thinking it is not a general FileDialog issue but has to do with the custom file dialog.
This is the relevant code:

Hi,
First of all thanks for the article.
I'm trying to use it with .net 4.0.
I changed some of the code according to MagnusO's comment but I'm still having different problems getting it to work, I think there is an issue with the DataContext property.
Did anyone get this to work?
dmihailescu, do you have any update plans for .net framework version 4.0?
Thanks,
Guy

Turns out the issue is not with the DataContext.
I did get it to work but there seems to be a problem with the location.
I set the following:
fd.FileDlgStartLocation = AddonWindowLocation.Right;

Yet the location of the custom content is not aligned correctly to the top.
The exact same code aligns correctly in .net 3.5, this is very weird.
I have some screen shots for this, I can not a find a way to attach them here so I'll send them by Email.
Any ideas?
Thanks,
Guy