如何从WPF应用程序使用FolderBrowserDialog

我试图从我的WPF应用程序使用FolderBrowserDialog – 没有什么奇特的。 我不太在乎它有Windows窗体的外观。

但是,当我打电话给ShowDialog,我想通过所有者窗口,这是一个IWin32Window。 我如何从我的WPF控件得到这个?

其实,这是否重要? 如果我运行这个代码,并使用ShowDialog重载没有参数,它工作正常。 在什么情况下我需要通过所有者窗口?

谢谢,

克雷格

这是我的最终版本。

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

如果指定了Owner,则将在指定的WPF窗口上获得一个Modal对话框。

为了得到WinForms兼容的Win32窗口创build一个类来实现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)); 

好的,现在就算出来了 – 谢谢Jobi,他的回答很接近,但不是很完美。

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

我敢肯定,我可以更好地包装起来,但基本上可以工作。 好极了! 🙂

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

我意识到这是一个古老的问题,但这是一个可能稍微更优雅的方法(以前可能或可能不会)…

 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可以提供一个可视的(可能是可听的)线索用户。

此外,它确保“正确的”窗口是有多个模式窗口(不是我主张这种UIdevise)。 我曾经见过一个由数十亿美元的公司devise的用户界面(这个界面仍然未命名),这个界面只是因为一个模式对话框被“卡住”在另一个之下而被吊死,用户甚至不知道如何closures它。

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 

传递所有者句柄的优点是FolderBrowserDialog不会模式到该窗口。 这可以防止用户在对话框处于活动状态时与主应用程序窗口进行交互。

通过使用PresentationSource.FromVisual并将结果转换为实现IWin32Window的HwndSource,您应该能够获得IWin32Window。

另外在这里的评论:

为什么不使用内置的WindowInteropHelper类(请参阅命名空间System.Windows.Interop)。 这个类已经推动了IWin32Window;)

所以你可以忘记“OldWindow类”…使用保持不变