我正在尝试从我的WPF应用程序使用FolderBrowserDialog,没什么复杂的。我并不在意它具有Windows Forms外观。
然而,当我调用ShowDialog时,我想传递拥有者窗口,它是一个IWin32Window。如何从我的WPF控件中获取它?
实际上,这重要吗?如果我运行此代码并使用没有参数的ShowDialog重载,则可以正常工作。在什么情况下需要传递所有者窗口?
谢谢,
Craig
我正在尝试从我的WPF应用程序使用FolderBrowserDialog,没什么复杂的。我并不在意它具有Windows Forms外观。
然而,当我调用ShowDialog时,我想传递拥有者窗口,它是一个IWin32Window。如何从我的WPF控件中获取它?
实际上,这重要吗?如果我运行此代码并使用没有参数的ShowDialog重载,则可以正常工作。在什么情况下需要传递所有者窗口?
谢谢,
Craig
这是我的最终版本。
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());
System.Windows.Interop
的 using 语句。 可以轻松扩展解决方案以与System.Windows.Forms.OpenFileDialog
一起使用。 同伴读者们 - 不要忘记检查DialogResult以确保用户没有单击“取消”按钮。 - sfuqua如果您指定所有者(Owner),则会在指定的WPF窗口上弹出模态对话框。
要获取与WinForms兼容的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));
我知道这是一个老问题,但是这里有一种方法可能会更加优雅(之前可能已经存在),...
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; }
}
}
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可以向用户提供视觉(可能还有听觉)提示。
此外,它确保在存在多个模态窗口时,“正确”的窗口处于顶部(尽管我不主张这样的UI设计)。我曾经见过某个多亿美元公司设计的UI,只因为一个模态对话框被“卡”在另一个对话框下面而挂起,用户甚至都不知道它的存在,更别说如何关闭它了。
using
指令吗? - Branko DimitrijevicGetIWin32Window
在那里被定义为扩展方法,因此在第二个代码片段中无需使用 using
就可以自动访问它(假设两个代码片段在同一个项目中)。 - Branko Dimitrijevic//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;
}
}
}
好的,现在我理解了 - 多亏了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);
我相信我可以更好地概括这个内容,但基本上它是有效的。耶! :-)
System.Windows.Forms.NativeWindow winForm;
public MainWindow()
{
winForm = new System.Windows.Forms.NativeWindow();
winForm.AssignHandle(new WindowInteropHelper(this).Handle);
...
}
public showDialog()
{
dlgFolderBrowser.ShowDialog(winForm);
}
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
你可以通过使用 PresentationSource.FromVisual 方法并将其结果转换为实现了 IWin32Window 接口的 HwndSource 来获取一个 IWin32Window。
此外,在 这里 的注释中也提到了: