2008-11-24 7 views
49

Я пытаюсь использовать FolderBrowserDialog из своего приложения WPF - ничего необычного. Мне все равно, что Windows Forms обращаются к нему.Как использовать FolderBrowserDialog из приложения WPF

Однако, когда я вызываю ShowDialog, я хочу передать окно владельца, которое является IWin32Window. Как мне получить это из моего WPF-элемента управления?

Собственно, это имеет значение? Если я запустил этот код и использую перегрузку ShowDialog без параметров, он отлично работает. При каких обстоятельствах мне нужно передать окно владельца?

Спасибо,

Craig

+2

Ознакомьтесь с фантастическим [Ookii.Dialogs] Свена Грота (как для WinForms и WPF, так и для WindowsForms и WPF). – 2012-03-02 19:01:51

ответ

54

И вот моя окончательная версия.

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()); 
+0

Когда я запускаю этот код, я получаю исключение Win32Exception, когда диалог закрывается. Кажется, это не проблема, и если я просто поймаю ее, все, похоже, сработает. Вы случайно знаете, почему это может быть брошено? – 2009-01-17 03:37:35

+0

Это действительно работает. – Nordes 2010-11-22 14:30:02

16

Если вы указываете владельца, вы получите модальный диалог по поводу указанного окна 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)); 
+0

Спасибо за это - это почти правильно - я отправлю ответ ниже. – 2008-11-24 20:23:46

+0

Это было точно и единственное, что здесь работало для меня. System.Windows.PresentationSource.FromVisual (визуальный) возвращал значение null. – 2010-11-10 22:20:38

+0

Это сработало отлично – eMi 2012-02-15 08:59:36

0

Преимущества пропускания владельца ручки является то, что FolderBrowserDialog не будет модальным для этого окна. Это предотвращает взаимодействие пользователя с вашим основным окном приложения, когда диалог активен.

0

Вы должны иметь возможность получать IWin32Window с помощью PresentationSource.FromVisual и выдавать результат в HwndSource, который реализует IWin32Window.

Также в комментариях here:

2

ОК, понял это сейчас - благодаря Джоби, чей ответ был близок, но не совсем.

Из приложения 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); 

Я уверен, что я могу оберните это лучше, но в основном это работает. Ура! :-)

+0

Попробуйте последние две строки из моего кода вместо этих 4 строк, я думаю, что это сработает для вас с нашим вызовом FromVisual. – 2008-11-24 20:43:30

0

Почему не с помощью встроенного в классе WindowInteropHelper (см пространства имен System.Windows.Interop). Этот класс уже impelements в IWin32Window;)

Таким образом, вы можете забыть о "OldWindow класса" ... использование остается тот же

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

VB.чистый перевод

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

Я понимаю, что это старый вопрос, но вот подход, который мог бы быть немного более элегантной (и могут или не могут быть доступны раньше) ...

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

    } 

} 

Тогда , из окна WPF, вы можете просто ...

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

} 

На самом деле, d Это важно?

Я не уверен, если это имеет значение в этом случае, но, как правило, вы должны сказать Windows, что иерархия окна, так что, если родительское окно щелкнуло в то время как дочернее окно является модальным, Windows может обеспечить визуальный (и, возможно, слышимый) ключ к пользователю.

Кроме того, это гарантирует, что «правильное» окно находится сверху, когда есть несколько модальных окон (не то, что я выступаю за такой дизайн пользовательского интерфейса). Я видел пользовательские интерфейсы, разработанные определенной многомиллиардной корпорацией (оболочка которой остается неназванной), которая висела просто потому, что один модальный диалог «застрял» под другим, и пользователь понятия не имел, что это было даже там, не говоря уже о том, как закрыть Это.

Смежные вопросы