Comment utiliser un FolderBrowserDialog à partir d'une application WPF
j'essaie d'utiliser le FolderBrowserDialog de mon application WPF - rien de fantaisiste. Je m'en fous qu'il ait les formes des fenêtres.
cependant, quand J'appelle ShowDialog, je veux passer la fenêtre du propriétaire qui est un IWin32Window. Comment puis-je obtenir ceci de mon contrôle WPF?
en fait, est-ce important? Si j'exécute ce code et que J'utilise la surcharge de ShowDialog sans paramètres, ça marche très bien. Dans quelles circonstances dois-je besoin de passer la fenêtre du propriétaire?
Merci,
Craig
9 réponses
et voici ma version finale.
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
}
}
et de l'utiliser effectivement:
var dlg = new FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window());
si vous spécifiez le propriétaire, vous obtiendrez un dialogue Modal sur la fenêtre WPF spécifiée.
pour obtenir WinForms compatible Win32 window créer une classe implémente IWin32Window comme ceci
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
}
et utilisez une instance de cette classe à vos WinForms
IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle; // 'this' means WPF Window
folderBrowserDialog.ShowDialog(new OldWindow(mainWindowPtr));
OK, compris maintenant-grâce à Jobi dont la réponse était proche, mais pas tout à fait.
D'une application WPF, voici mon code qui fonctionne:
d'Abord une classe helper:
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
}
ensuite, pour utiliser ceci:
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);
je suis sûr que je peux mieux terminer, mais en gros ça marche. Yay!!! :- )
//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;
}
}
}
je me rends compte que c'est une vieille question, Mais voici une approche qui pourrait être un peu plus élégante (et peut-être ou peut-être pas disponible avant)...
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; }
}
}
alors, de votre fenêtre WPF, vous pouvez simplement...
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.
}
}
}
}
est-ce important?
Je ne suis pas sûr que ce soit important dans ce cas , mais en général, vous devriez dites à Windows Quelle est votre hiérarchie de fenêtre, donc si une fenêtre parent est cliquée alors que la fenêtre enfant est modale, Windows peut fournir un indice visuel (et peut-être audible) à l'utilisateur.
aussi, il s'assure que la fenêtre" droit " est sur le dessus quand il ya plusieurs fenêtres modales (pas que je préconise une telle conception de L'UI). J'ai vu UIs conçu par une certaine société multi-milliards de dollars (dont shell reste anonyme), qui a pendu simplement parce qu'un dialogue modal a été "coincé" en dessous de l'autre, et l'utilisateur n'a aucune idée qu'il était encore là, et encore moins comment le fermer.
VB.net traduction
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
l'avantage de passer une poignée de propriétaire est que le FolderBrowserDialog ne sera pas modal à cette fenêtre. Cela empêche l'utilisateur d'interagir avec votre fenêtre d'application principale pendant que le dialogue est actif.