it-swarm.com.de

So verwenden Sie einen FolderBrowserDialog aus einer WPF-Anwendung

Ich versuche, den FolderBrowserDialog aus meiner WPF-Anwendung zu verwenden - nichts Besonderes. Es ist mir egal, dass es so aussieht wie Windows Forms.

Wenn ich ShowDialog aufrufe, möchte ich jedoch das Besitzerfenster übergeben, das ein IWin32Window ist. Wie bekomme ich das von meinem WPF-Steuerelement?

Ist es eigentlich wichtig? Wenn ich diesen Code ausführe und die ShowDialog-Überladung ohne Parameter verwende, funktioniert es einwandfrei. Unter welchen Umständen muss ich das Besitzerfenster passieren?

Vielen Dank,

Craig

51
Craig Shearer

Und hier ist meine endgültige 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
    }
}

Und um es tatsächlich zu benutzen:

var dlg = new FolderBrowserDialog();
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window());
57
Craig Shearer

Wenn Sie Besitzer angeben, wird über das angegebene WPF-Fenster ein modales Dialogfeld angezeigt.

Um WinForms-kompatibles Win32-Fenster zu erhalten, implementiert eine Klasse IWin32Window wie folgt

 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
}

Verwenden Sie eine Instanz dieser Klasse in Ihren WinForms

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

Mir ist klar, dass dies eine alte Frage ist, aber hier ist ein Ansatz, der vielleicht etwas eleganter ist (und vielleicht vorher verfügbar war oder nicht) ...

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

    }

}

Dann können Sie in Ihrem WPF-Fenster einfach ...

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

}

Ist es eigentlich wichtig?

Ich bin nicht sicher, ob es darauf ankommt in diesem Fall, aber im Allgemeinen sollten Sie Windows mitteilen, wie Ihre Fensterhierarchie lautet. Wenn also auf ein übergeordnetes Fenster geklickt wird, während das untergeordnete Fenster modal ist, kann Windows eine visuelle Darstellung bereitstellen (und möglicherweise hörbaren) Hinweis auf den Benutzer.

Außerdem wird sichergestellt, dass das "rechte" Fenster oben ist, wenn mehrere modale Fenster vorhanden sind (nicht, dass ich ein solches UI-Design befürworte). Ich habe Benutzeroberflächen gesehen, die von einem Milliarden-Dollar-Unternehmen entwickelt wurden (von denen Shell noch keinen Namen hat), die einfach daran hingen, dass ein modaler Dialog unter dem anderen "hängen blieb" und der Benutzer keine Ahnung hatte, dass er selbst dort war, geschweige denn, wie er geschlossen werden sollte es.

3
//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
Bruno

OK, habe es jetzt herausgefunden - dank Jobi, dessen Antwort nah, aber nicht ganz war.

In einer WPF-Anwendung ist hier mein Code, der funktioniert:

Zuerst eine Helferklasse:

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
}

Um dies zu verwenden:

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

Ich bin mir sicher, dass ich das besser einpacken kann, aber im Grunde funktioniert es. Yay! :-)

2
Craig Shearer

VB.net Übersetzung

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
1
user2307482

Verwenden Sie die integrierte WindowInteropHelper-Klasse (siehe Namespace System.Windows.Interop). Diese Klasse enthält bereits das IWin32Window;)

So können Sie die "OldWindow-Klasse" vergessen ... die Verwendung bleibt gleich

0
Kenshin

Der Vorteil der Übergabe eines Besitzer-Handles besteht darin, dass der FolderBrowserDialog für dieses Fenster nicht modal ist. Dies verhindert, dass der Benutzer mit Ihrem Hauptanwendungsfenster interagiert, während das Dialogfeld aktiv ist.

0
Andy

Sie sollten in der Lage sein, ein IWin32Window zu erhalten, indem Sie PresentationSource.FromVisual verwenden und das Ergebnis in HwndSource umwandeln, das IWin32Window implementiert.

Auch in den Kommentaren hier :

0
jageall

Hier ist eine einfache Methode.


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
Shangwu