How to use a FolderBrowserDialog from a WPF application

Viewed 114153

I'm trying to use the FolderBrowserDialog from my WPF application - nothing fancy. I don't much care that it has the Windows Forms look to it.

However, when I call ShowDialog, I want to pass the owner window which is an IWin32Window. How do I get this from my WPF control?

Actually, does it matter? If I run this code and use the ShowDialog overload with no parameters it works fine. Under what circumstances do I need to pass the owner window?

Thanks,

Craig

10 Answers

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());

If you specify Owner, you will get a Modal dialog over the specified WPF window.

To get WinForms compatible Win32 window create a class implements IWin32Window like this

 public class OldWindow : System.Windows.Forms.IWin32Window
{
    IntPtr _handle;

    public OldWindow(IntPtr handle)
    {
        _handle = handle;
    }

    #region IWin32Window Members

    IntPtr System.Windows.Forms.IWin32Window.Handle
    {
        get { return _handle; }
    }

    #endregion
}

And use an instance of this class at your WinForms

        IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle; // 'this' means WPF Window
        folderBrowserDialog.ShowDialog(new OldWindow(mainWindowPtr));

OK, figured it out now - thanks to Jobi whose answer was close, but not quite.

From a WPF application, here's my code that works:

First a helper class:

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

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

Then, to use this:

    System.Windows.Forms.FolderBrowserDialog dlg = new FolderBrowserDialog();
    HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
    System.Windows.Forms.IWin32Window win = new OldWindow(source.Handle);
    System.Windows.Forms.DialogResult result = dlg.ShowDialog(win);

I'm sure I can wrap this up better, but basically it works. Yay! :-)

Here is a simple method.

System.Windows.Forms.NativeWindow winForm; 

public MainWindow()
{
    winForm = new System.Windows.Forms.NativeWindow();
    winForm.AssignHandle(new WindowInteropHelper(this).Handle);
    ...
}

public showDialog()
{
   dlgFolderBrowser.ShowDialog(winForm);
}

The advantage of passing an owner handle is that the FolderBrowserDialog will not be modal to that window. This prevents the user from interacting with your main application window while the dialog is active.

You should be able to get an IWin32Window by by using PresentationSource.FromVisual and casting the result to HwndSource which implements IWin32Window.

Also in the comments here:

Why not using the built in WindowInteropHelper class (see namespace System.Windows.Interop). This class already impelements the IWin32Window ;)

So you can forget about the "OldWindow class" ... the usage stays the same

Related