Using Folderbrowserdialog in Wpf Application

Using FolderBrowserDialog in WPF application

You need to add a reference to System.Windows.Forms.dll, then use the System.Windows.Forms.FolderBrowserDialog class.

Adding using WinForms = System.Windows.Forms; will be helpful.

How to use a FolderBrowserDialog from a WPF application

And here's my final version.

public static class MyWpfExtensions
{
public static System.Windows.Forms.IWin32Window GetIWin32Window(this System.Windows.Media.Visual visual)
{
var source = System.Windows.PresentationSource.FromVisual(visual) as System.Windows.Interop.HwndSource;
System.Windows.Forms.IWin32Window win = new OldWindow(source.Handle);
return win;
}

private class OldWindow : System.Windows.Forms.IWin32Window
{
private readonly System.IntPtr _handle;
public OldWindow(System.IntPtr handle)
{
_handle = handle;
}

#region IWin32Window Members
System.IntPtr System.Windows.Forms.IWin32Window.Handle
{
get { return _handle; }
}
#endregion
}
}

And to actually use it:

var dlg = new FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window());

How to use a FolderBrowserDialog from a WPF application with MVVM

First, you could use the ShowDialog signature that does not require a window.

var dlg = new FolderBrowserDialog();
DialogResult result = dlg.ShowDialog();

Second, you could send the main window of the Application as the owning window.

var dlg = new FolderBrowserDialog();
DialogResult result = dlg.ShowDialog(Application.Current.MainWindow.GetIWin32Window());

The second option might not be considered very MVVMish.

See the answer by @Dr. ABT in this question for a way to inject a pointer to your View into your ViewModel (not sure if this is a good idea or a bad idea, but I'm not going to let that stop me) With this technique, you would have access in your VM to the corresponding View if you really want to make that View be the owner of the FolderBrowserDialog.

@ChrisDD is right about defining an interface and wrapping FolderBrowserDialog. That is how we do it:

  public interface IFolderBrowserDialog
{
string Description { get; set; }
Environment.SpecialFolder RootFolder { get; set; }
string SelectedPath { get; set; }
bool ShowNewFolderButton { get; set; }
bool? ShowDialog();
bool? ShowDialog(Window owner);
}

//Decorated for MEF injection
[Export(typeof(IFolderBrowserDialog))]
[PartCreationPolicy(CreationPolicy.NonShared)]
internal class WindowsFormsFolderBrowserDialog : IFolderBrowserDialog
{
private string _description;
private string _selectedPath;

[ImportingConstructor]
public WindowsFormsFolderBrowserDialog()
{
RootFolder = System.Environment.SpecialFolder.MyComputer;
ShowNewFolderButton = false;
}

#region IFolderBrowserDialog Members

public string Description
{
get { return _description ?? string.Empty; }
set { _description = value; }
}

public System.Environment.SpecialFolder RootFolder { get; set; }

public string SelectedPath
{
get { return _selectedPath ?? string.Empty; }
set { _selectedPath = value; }
}

public bool ShowNewFolderButton { get; set; }

public bool? ShowDialog()
{
using (var dialog = CreateDialog())
{
var result = dialog.ShowDialog() == DialogResult.OK;
if (result) SelectedPath = dialog.SelectedPath;
return result;
}
}

public bool? ShowDialog(Window owner)
{
using (var dialog = CreateDialog())
{
var result = dialog.ShowDialog(owner.AsWin32Window()) == DialogResult.OK;
if (result) SelectedPath = dialog.SelectedPath;
return result;
}
}
#endregion

private FolderBrowserDialog CreateDialog()
{
var dialog = new FolderBrowserDialog();
dialog.Description = Description;
dialog.RootFolder = RootFolder;
dialog.SelectedPath = SelectedPath;
dialog.ShowNewFolderButton = ShowNewFolderButton;
return dialog;
}
}

internal static class WindowExtensions
{
public static System.Windows.Forms.IWin32Window AsWin32Window(this Window window)
{
return new Wpf32Window(window);
}
}

internal class Wpf32Window : System.Windows.Forms.IWin32Window
{
public Wpf32Window(Window window)
{
Handle = new WindowInteropHelper(window).Handle;
}

#region IWin32Window Members

public IntPtr Handle { get; private set; }

#endregion
}

Then we make the VM/Command where we want to use the FolderBrowser import IFolderBrowserDialog. In application, IFolderBrowserDialog.ShowDialog shows the dialog. In unit test, we mock IFolderBrowserDialog so we can verify that it was called with correct parameters and/or send the selected folder back to the sut so that the test can continue.

Is it possible to use FolderBrowserDialog in a WPF Net 6 application?

.NET 5 and .NET 6 are still .NET Core and don't require a specific IDE to compile. Project settings are stored in the csproj file and can be edited even with any text editor.

You can inspect the contents of the .NET 5 project and copy any settings you need to the .NET 6 project. Or you can simply change the project's target from net5.0 to net6.0.

In this case the setting is

<UseWindowsForms>true</UseWindowsForms>

Is Owner Window required in WPF FolderBrowserDialog in 2021?

Actually, is the Win32 Api REALLY required

Yes. The FolderBrowserDialog is exposed through Win32. You can't write software for Windows without using Win32 in some way or another.

I just tried the FolderBrowserDialog and it is already modal by default; simply calling .ShowDialog() is already modal to the underlying window.

That's because when you call ShowDialog() it passes IntPtr.Zero for the owner hWnd parameter (the same as NULL in C). When you pass NULL then Windows uses the currently active window in the process as the owner - so an owner is still set, it's just determined automatically:

From the documentation for WinForms' ShowDialog() (the overload without the owner parameter. While WinForms and WPF are separate, the principle is the same for both):

When this version is called, the currently active window is made the owner of the dialog box. If you want to specify a specific owner, use the other version of this method.

That said, you should still specify the owner hWnd where possible because you may rearchitect your application and may want a different window to be the owner (e.g. when you want to show a dialog immediately after the non-root parent window closes)

Open directory dialog

You can use the built-in FolderBrowserDialog class for this. Don't mind that it's in the System.Windows.Forms namespace.

using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
{
System.Windows.Forms.DialogResult result = dialog.ShowDialog();
}

If you want the window to be modal over some WPF window, see the question How to use a FolderBrowserDialog from a WPF application.


EDIT: If you want something a bit more fancy than the plain, ugly Windows Forms FolderBrowserDialog, there are some alternatives that allow you to use the Vista dialog instead:

  • Third-party libraries, such as Ookii dialogs (.NET 4.5+)

  • The Windows API Code Pack-Shell:

      using Microsoft.WindowsAPICodePack.Dialogs;

    ...

    var dialog = new CommonOpenFileDialog();
    dialog.IsFolderPicker = true;
    CommonFileDialogResult result = dialog.ShowDialog();

    Note that this dialog is not available on operating systems older than Windows Vista, so be sure to check CommonFileDialog.IsPlatformSupported first.

FolderBrowserDialog in wpf c#

You can use the FolderBrowserDialog; either explicitly place the namespace in front of the class...

System.Windows.Forms.FolderBrowserDialog browse = new System.Windows.Forms.FolderBrowserDialog();

...or create an alias with regard to your namespace.

Imports [ aliasname = ] namespace


Related Topics



Leave a reply



Submit