Как использовать FolderBrowserDialog из приложения WPF - PullRequest
50 голосов
/ 24 ноября 2008

Я пытаюсь использовать FolderBrowserDialog из моего приложения WPF - ничего особенного. Мне все равно, что Windows Forms выглядит так.

Однако, когда я вызываю ShowDialog, я хочу передать окно владельца, которое является IWin32Window. Как я могу получить это из моего элемента управления WPF?

На самом деле, это имеет значение? Если я запускаю этот код и использую перегрузку ShowDialog без параметров, он работает нормально. При каких обстоятельствах мне нужно передать окно владельца?

Спасибо

Craig

Ответы [ 10 ]

57 голосов
/ 24 ноября 2008

А вот и мой окончательный вариант.

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
    }
}

И чтобы фактически использовать это:

var dlg = new FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window());
16 голосов
/ 24 ноября 2008

Если вы укажете «Владелец», вы получите модальное диалоговое окно поверх указанного окна WPF.

Чтобы получить Win32ms-совместимое окно Win32, создайте класс, реализующий IWin32Window следующим образом

 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
}

И используйте экземпляр этого класса на своей WinForms

        IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle; // 'this' means WPF Window
        folderBrowserDialog.ShowDialog(new OldWindow(mainWindowPtr));
3 голосов
/ 09 мая 2016

Я понимаю, что это старый вопрос, но вот подход, который может быть немного более элегантным (и может быть, а может и не был доступен раньше) ...

using System;
using System.Windows;
using System.Windows.Forms;

// ...

/// <summary>
///     Utilities for easier integration with WinForms.
/// </summary>
public static class WinFormsCompatibility {

    /// <summary>
    ///     Gets a handle of the given <paramref name="window"/> and wraps it into <see cref="IWin32Window"/>,
    ///     so it can be consumed by WinForms code, such as <see cref="FolderBrowserDialog"/>.
    /// </summary>
    /// <param name="window">
    ///     The WPF window whose handle to get.
    /// </param>
    /// <returns>
    ///     The handle of <paramref name="window"/> is returned as <see cref="IWin32Window.Handle"/>.
    /// </returns>
    public static IWin32Window GetIWin32Window(this Window window) {
        return new Win32Window(new System.Windows.Interop.WindowInteropHelper(window).Handle);
    }

    /// <summary>
    ///     Implementation detail of <see cref="GetIWin32Window"/>.
    /// </summary>
    class Win32Window : IWin32Window { // NOTE: This is System.Windows.Forms.IWin32Window, not System.Windows.Interop.IWin32Window!

        public Win32Window(IntPtr handle) {
            Handle = handle; // C# 6 "read-only" automatic property.
        }

        public IntPtr Handle { get; }

    }

}

Затем из окна WPF вы можете просто ...

public partial class MainWindow : Window {

    void Button_Click(object sender, RoutedEventArgs e) {
        using (var dialog = new FolderBrowserDialog()) {
            if (dialog.ShowDialog(this.GetIWin32Window()) == System.Windows.Forms.DialogResult.OK) {
                // Use dialog.SelectedPath.
            }
        }
    }

}

На самом деле, это имеет значение?

Я не уверен, имеет ли это значение в данном случае , но, как правило, вы должны указать Windows, какова ваша иерархия окон, поэтому, если щелкнуть родительское окно, в то время как дочернее окно модально, Windows может предоставить визуальная (и, возможно, слышимая) подсказка для пользователя.

Кроме того, он гарантирует, что «правильное» окно находится сверху при наличии нескольких модальных окон (не то, чтобы я выступал за такой дизайн пользовательского интерфейса). Я видел пользовательские интерфейсы, разработанные некой многомиллиардной корпорацией (эта оболочка осталась безымянной), которая зависла просто потому, что один модальный диалог «застрял» под другим, и пользователь не имел ни малейшего представления, что он даже там, не говоря уже о том, как закрыть это.

2 голосов
/ 27 июля 2010
//add a reference to System.Windows.Forms.dll

public partial class MainWindow : Window, System.Windows.Forms.IWin32Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void button_Click(object sender, RoutedEventArgs e)
    {
        var fbd = new FolderBrowserDialog();
        fbd.ShowDialog(this);
    }

    IntPtr System.Windows.Forms.IWin32Window.Handle
    {
        get
        {
            return ((HwndSource)PresentationSource.FromVisual(this)).Handle;
        }
    }
}
2 голосов
/ 24 ноября 2008

Ладно, понял это сейчас - благодаря Джоби, чей ответ был близок, но не совсем.

Из приложения WPF вот мой код, который работает:

Первый класс помощника:

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
}

Затем, чтобы использовать это:

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

Я уверен, что могу обернуть это лучше, но в основном это работает. Ура! : -)

1 голос
/ 10 апреля 2014

VB.net перевод

Module MyWpfExtensions

Public Function GetIWin32Window(this As Object, visual As System.Windows.Media.Visual) As System.Windows.Forms.IWin32Window

    Dim source As System.Windows.Interop.HwndSource = System.Windows.PresentationSource.FromVisual(Visual)
    Dim win As System.Windows.Forms.IWin32Window = New OldWindow(source.Handle)
    Return win
End Function

Private Class OldWindow
    Implements System.Windows.Forms.IWin32Window

    Public Sub New(handle As System.IntPtr)
        _handle = handle
    End Sub


    Dim _handle As System.IntPtr
    Public ReadOnly Property Handle As IntPtr Implements Forms.IWin32Window.Handle
        Get

        End Get
    End Property


End Class

End Module
0 голосов
/ 10 апреля 2019

Вот простой метод.


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

0 голосов
/ 08 июля 2009

Почему бы не использовать встроенный класс WindowInteropHelper (см. Пространство имен System.Windows.Interop). Этот класс уже реализует IWin32Window;)

Так что вы можете забыть о «классе OldWindow» ... использование остается прежним

0 голосов
/ 24 ноября 2008

Вы должны иметь возможность получить IWin32Window, используя PresentationSource.FromVisual и приведя результат к HwndSource, который реализует IWin32Window.

Также в комментариях здесь :

0 голосов
/ 24 ноября 2008

Преимущество передачи дескриптора владельца заключается в том, что FolderBrowserDialog не будет модальным для этого окна. Это предотвращает взаимодействие пользователя с главным окном приложения, когда диалоговое окно активно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...