2008-11-24 22 views
49

Estoy tratando de usar el FolderBrowserDialog desde mi aplicación WPF: nada elegante. No me importa mucho que tenga el aspecto de Windows Forms.Cómo usar un FolderBrowserDialog desde una aplicación WPF

Sin embargo, cuando llamo a ShowDialog, quiero pasar la ventana del propietario que es una IWin32Window. ¿Cómo obtengo esto de mi control WPF?

¿Realmente importa? Si ejecuto este código y uso la sobrecarga ShowDialog sin parámetros, funciona bien. ¿Bajo qué circunstancias necesito pasar la ventana del propietario?

Gracias,

Craig

+2

Salida de Sven Groot fantástica [Ookii.Dialogs] (http://www.ookii.org/software/dialogs/) tanto para Windows Forms y WPF, que le dan modernos cuadros de diálogo "Vista" carpeta estilo y archivos. –

Respuesta

54

Y esta es mi versión final.

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

Y que realmente se utilicen:

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

Cuando ejecuto este código, obtengo una excepción Win32Exception cada vez que se cierra el cuadro de diálogo. No parece ser un problema, y ​​si simplemente lo veo, todo parece funcionar. ¿Sabes por qué podría ser arrojado? –

+0

Realmente funciona bien. – Nordes

+0

Parece que funciona bien, pero no puedo ver ningún punto para mí, llamar con 0 argumentos todavía muestra el 'mismo' diálogo modal. – John

16

Si especifica propietario, recibirá un cuadro de diálogo modal sobre la ventana de WPF especificado.

Para obtener WinForms ventana Win32 compatibles crear una clase implementa IWin32Window como esto

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 
} 

y utilizar una instancia de esta clase en su WinForms

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

Gracias por esto, es casi correcto, publicaré una respuesta a continuación. –

+0

Esto fue exactamente lo correcto y lo único que funcionó para mí. System.Windows.PresentationSource.FromVisual (visual) devolvió nulo. –

+0

esto funcionó bien – eMi

0

La ventaja de pasar un mango propietario es que el FolderBrowserDialog no será modal para esa ventana. Esto evita que el usuario interactúe con la ventana principal de la aplicación mientras el cuadro de diálogo está activo.

0

Debería poder obtener un IWin32Window utilizando PresentationSource.FromVisual y enviando el resultado a HwndSource que implementa IWin32Window.

también en los comentarios here:

2

OK, lo descubrió ahora - gracias a Jobi cuya respuesta estaba cerca, pero no del todo.

Desde una aplicación de WPF, aquí es mi código que funciona:

En primer lugar una clase de ayuda:

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 
} 

Entonces, para utilizar este:

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

estoy seguro de que pueda termine esto mejor, pero básicamente funciona. ¡Hurra! :-)

+0

Prueba las dos últimas líneas de mi código en lugar de esto 4 líneas, creo que va a trabajar para usted con nuestra la llamada FromVisual. –

0

Por qué no usar el (ver System.Windows.Interop espacio de nombres) incorporado en la clase WindowInteropHelper. Esta clase ya impelements la IWin32Window;)

Así que usted puede olvidarse de la "clase OldWindow" ... el uso sigue siendo el mismo

+0

Quizás solía hacerlo, pero en .NET 4 no. – 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

¿Esto funciona con wpf? No puedo hacer que funcione; ¿Este código no funciona solo en los formularios de Windows? – Malavos

1

VB.Traducción neta

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

Comprendo que esto es una vieja pregunta, pero aquí es un enfoque que podría ser un poco más elegante (y puede o no haber estado disponible antes) ...

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

    } 

} 

Entonces , desde la ventana de WPF, puede simplemente ...

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

} 

En realidad, d ¿Qué importa?

no estoy seguro si importa en este caso , pero en general, se debe indicar a Windows cuál es la jerarquía de la ventana, por lo que si se hace clic en una ventana padre mientras ventana secundaria es modal, Windows puede proporcionar una pista visual (y posiblemente audible) para el usuario.

Además, se garantiza la ventana "derecho" es en la parte superior cuando hay varias ventanas modales (no es que yo estoy abogando por ejemplo el diseño de UI). He visto UI diseñadas por una determinada corporación multimillonaria (cuyo shell no se menciona), que se colgaron simplemente porque un diálogo modal se "atascó" debajo de otro, y el usuario no tenía ni idea de que estaba allí, y mucho menos de cómo cerrar eso.

+0

¿Qué uso usas para esto? GetIWin32Window()? – StuiterSlurf

+0

@StuiterSlurf No estoy seguro de entender la pregunta. ¿Están preguntando sobre una directiva 'using'? –

+0

Sí. Mi Visual Studio no dice lo que necesito utilizar para obtener de este – StuiterSlurf

Cuestiones relacionadas