Как использовать FolderBrowserDialog из приложения WPF

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

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

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

Спасибо,

Крейг

Ознакомьтесь с фантастическим Ookii.Dialogs Свена Гроота для WinForms и WPF, который дает вам современные диалоговые окна папок и файлов в стиле Vista.

David Cuccia 02.03.2012 23:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
54
1
106 381
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

Если вы укажете «Владелец», вы получите модальное диалоговое окно в указанном окне WPF.

Чтобы получить окно Win32, совместимое с WinForms, создайте класс, реализующий 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));

Спасибо за это - это почти правильно - я опубликую ответ ниже.

Craig Shearer 24.11.2008 23:23

Это было абсолютно правильно и единственное, что работало для меня. System.Windows.PresentationSource.FromVisual (визуальный) возвращал значение null.

Mike Blandford 11.11.2010 01:20

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

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

Также в комментариях здесь:

Хорошо, теперь разобрался - спасибо Джоби, чей ответ был близок, но не совсем.

Вот мой работающий код из приложения 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);

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

Попробуйте последние две строки из моего кода вместо этих 4 строк, я думаю, это сработает для вас с нашим вызовом FromVisual.

Jobi Joy 24.11.2008 23:43
Ответ принят как подходящий

И вот моя последняя версия.

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

Когда я запускаю этот код, я получаю исключение Win32Exception при закрытии диалогового окна. Кажется, это не проблема, и если я просто поймаю это, все вроде работает. Вы случайно не знаете, почему это может быть брошено?

Scott Wisniewski 17.01.2009 06:37

Кажется, все работает нормально, но я сам не вижу в этом никакого смысла, вызов с 0 аргументами по-прежнему показывает «тот же» модальный диалог.

John 10.09.2011 02:42

Работал у меня прекрасно, без исключений (.Net 3.5). Пришлось добавить оператор using для System.Windows.Interop. Легко расширить решение для использования с System.Windows.Forms.OpenFileDialog. Друзья, читатели - не забудьте проверить DialogResult, чтобы убедиться, что пользователь не нажимал кнопку «Отмена».

sfuqua 15.10.2011 02:33

В моем событии Button это сработало: dlg.ShowDialog (this.GetIWin32Window (this));

Farrukh Waheed 24.03.2014 16:12

Даже не смог бы скомпилировать без предложения Фарруха ... приведенный выше код использования неверен в том, что при вызове GetIWin32Window (????) не указан параметр.

Jon 19.09.2016 20:45

Почему бы не использовать встроенный класс WindowInteropHelper (см. Пространство имен System.Windows.Interop). Этот класс уже реализует IWin32Window;)

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

Возможно, раньше, но в .NET 4 это не так.

MoonStom 11.03.2016 20:38
//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;
        }
    }
}

Это работает с wpf? Я не могу заставить его работать; Разве этот код не работает только в формах Windows?

Malavos 30.04.2014 17:02

Перевод VB.net

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

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

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

}

Actually, does it matter?

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

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

Что вы используете для этого. GetIWin32Window ()?

StuiterSlurf 30.06.2017 17:17

@StuiterSlurf Я не уверен, что понимаю вопрос. Спрашиваете о директиве using?

Branko Dimitrijevic 30.06.2017 18:00

да. Моя Visual Studio не говорит, что мне нужно для этого

StuiterSlurf 30.06.2017 18:03

@StuiterSlurf Посмотрите на первый фрагмент кода - GetIWin32Window определен там как метод расширения, поэтому он автоматически доступен из второго фрагмента без using (при условии, что оба фрагмента находятся в одном проекте).

Branko Dimitrijevic 30.06.2017 18:08

Вот простой способ.


System.Windows.Forms.NativeWindow winForm; 
public MainWindow()
{
    winForm = new System.Windows.Forms.NativeWindow();
    winForm.AssignHandle(new WindowInteropHelper(this).Handle);
    ...
}
public showDialog()
{
   dlgFolderBrowser.ShowDialog(winForm);
}

Другие вопросы по теме