2008-11-24 2 views
49

Ich versuche, den FolderBrowserDialog von meiner WPF-Anwendung zu verwenden - nichts Schickes. Es ist mir egal, dass Windows Forms so aussieht.Wie man einen FolderBrowserDialog aus einer WPF-Anwendung verwendet

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

Eigentlich spielt es eine Rolle? Wenn ich diesen Code ausführen und die ShowDialog-Überladung ohne Parameter verwenden, funktioniert es einwandfrei. Unter welchen Umständen muss ich das Besitzerfenster übergeben?

Danke,

Craig

+2

Schauen Sie sich Sven Groot fantastische [Ookii.Dialogs] (http://www.ookii.org/software/dialogs/) für beide WinForms und WPF, die Ihnen moderne „Vista“ Stil-Ordner und Dateidialoge geben. –

Antwort

54

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 tatsächlich, es zu benutzen:

var dlg = new FolderBrowserDialog(); 
System.Windows.Forms.DialogResult result = dlg.ShowDialog(this.GetIWin32Window()); 
+0

Wenn ich diesen Code ausführen, bekomme ich eine Win32Exception ausgelöst, wenn das Dialogfeld geschlossen wird. Es scheint kein Problem zu sein, und wenn ich es gerade erwische, scheint alles zu funktionieren. Weißt du zufällig, warum das ausgelöst werden könnte? –

+0

Es funktioniert tatsächlich gut. – Nordes

+0

Scheint gut zu funktionieren, aber ich kann selbst keinen Punkt erkennen, der Aufruf mit 0 Argumenten zeigt immer noch den gleichen modalen Dialog. – John

16

Wenn Sie Besitzer angeben, werden Sie ein Modal Dialog über den angegebenen WPF-Fenster.

Um WinForms kompatibel Win32 Fenster erstellen Klasse implementiert IWin32Window wie diese

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 
} 

Und verwenden Sie eine Instanz dieser Klasse an Ihrer WinForms

 IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle; // 'this' means WPF Window 
     folderBrowserDialog.ShowDialog(new OldWindow(mainWindowPtr)); 
+0

Danke dafür - es ist fast richtig - ich werde eine Antwort unten posten. –

+0

Das war genau richtig und das einzige, was hier für mich funktionierte. System.Windows.PresentationSource.FromVisual (visuell) gab null zurück. –

+0

diese fein gearbeitet – eMi

0

Der Vorteil der Übergabe eines Eigentümers Griff zu bekommen, ist, dass Der FolderBrowserDialog wird für dieses Fenster nicht modal sein. Dies verhindert, dass der Benutzer mit dem Hauptfenster der Anwendung interagiert, während das Dialogfeld aktiv ist.

0

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

Auch in den Kommentaren here:

2

OK, dachte es jetzt - dank Jobi, deren Antwort war in der Nähe, aber nicht ganz.

Von einer WPF-Anwendung, hier ist mein Code, das funktioniert:

Zuerst wird eine Hilfsklasse:

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 
} 

Dann ist dieses 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 sicher, ich kann Wrap dies besser, aber im Grunde funktioniert es. Yay! :-)

+0

die letzten beiden Zeilen von meinem Code Versuchen Sie statt dieser vier Linien, ich denke, es mit unseren dem FromVisual Anruf für Sie arbeiten. –

0

Warum in WindowInteropHelper Klasse des eingebauten nicht mit (Namespace System.Windows.Interop sehen). Diese Klasse bereits impelements die IWin32Window;)

So können Sie über die "OldWindow Klasse" vergessen ... die Nutzung bleibt gleich

+0

Vielleicht ist es so, aber in .NET 4 nicht. – MoonStom

2
//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; 
     } 
    } 
} 
+0

Funktioniert das mit wpf? Ich kann es nicht funktionieren lassen; Funktioniert dieser Code nicht nur in Windows-Formularen? – Malavos

1

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 
2

Ich weiß, das eine alte Frage, aber hier ist ein Ansatz, der etwas elegantere sein könnte (und kann oder nicht, bevor vorhanden gewesen sein kann) ...

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 , aus dem WPF-Fenster, können Sie 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. 
      } 
     } 
    } 

} 

Eigentlich d ist es wichtig?

Ich bin mir nicht sicher, ob es in diesem Fall zählt, aber im Allgemeinen sollten Sie Windows sagen, was ist Ihr Fenster Hierarchie, so dass, wenn ein übergeordnetes Fenster geklickt wird, während Kind Fenster modal sind, Windows-a zur Verfügung stellen kann visueller (und möglicherweise hörbarer) Hinweis für den Benutzer.

Außerdem sorgt sie für das „richtige“ Fenster oben ist, wenn mehrere modale Fenster sind (nicht, dass ich eine solche UI-Design bin befürworten). Ich habe UIs um ein bestimmtes Multi-Milliarden-Dollar-Unternehmen (die Schale bleiben unbenannt), dass gehängt, nur weil ein modaler Dialog bekam „stecken“ unter einem anderen entworfen gesehen, und Benutzer hatte keine Ahnung, es selbst dort war, geschweige denn, wie zu schließen es.

+0

Was verwenden Sie dafür.GetIWin32Window()? – StuiterSlurf

+0

@StuiterSlurf Ich bin mir nicht sicher, ob ich die Frage verstehe. Fragen Sie nach einer Verwendungsrichtlinie? –

+0

Ja. Mein Visual Studio sagt nicht, welche Verwendung ich für dieses – StuiterSlurf

Verwandte Themen