Учитывая, что ваш вопрос помечен c # , у вас есть весь .NET Framework, который предоставляет встроенную функциональность для отображения окон (форм) в виде модальных диалогов.Нет причин, по которым вам для этого нужно вызывать функции из API Windows.
В общем, единственная причина, по которой функции P / Invoke из API Windows - это использовать функции, которые еще не были представлены в управляемом коде.,Обычному приложению придется делать это очень редко, а базовые сценарии использования, такие как показ модального диалога, безусловно, не требуют этого.
Способ сделать это в C # (или любом другом языке .NET) - изменитьспособ показать форму в вопросе.Вместо вызова метода Form.Show
следует использовать метод Form.ShowDialog
.
Доступны две перегрузки. first не принимает параметров и устанавливает для владельца диалогового окна текущее активное окно. секунда принимает один параметр, который определяет окно, которому будет принадлежать это диалоговое окно.
Свойство Form.Modal
обеспечивает быстрый способ проверки, чтобы увидеть, действительно лиформа отображается модально.Однако, как отмечается в документации, он доступен только для чтения.Единственный способ отобразить форму модально - это вызвать метод ShowDialog
, как обсуждалось выше.
Что касается решения Windows API, нет такой функции, которую можно вызвать.Окно не может быть преобразовано в модальное диалоговое окно после того, как оно было создано.Вы должны отобразить это таким образом изначально.В приложении Win32 вы делаете это, вызывая функцию DialogBox
(в отличие от CreateDialog
).
MFC показывает модальное диалоговое окно с использованием CDialog::DoModal
функция , но она не отображает модальное диалоговое окно.Вместо этого он использует хак для создания модального диалогового окна pseudo (или имитации), которое включает в себя отключение окна владельца, запуск собственного цикла сообщений в методе DoModal
и ожидание предварительно определенной сериисобытия, которые заставляют модальный цикл выйти изящно.Я не рекомендую делать это в вашем собственном приложении.Это просто не нужно, и слишком легко ошибиться.В подходе MFC было / было достаточно ошибок, и эта команда полностью знала внутренние компоненты Win32.
Метод ShowDialog
в WinForms работает на модели, очень похожей на модель MFC.Ответ Ханса здесь дает дополнительную информацию.Обратите внимание, что если вы собираетесь реализовать свой собственный модальный цикл диалога, вам нужно не забыть снова включить окно владельца сначала , а затем уничтожить модальное диалоговое окно.Если вы не сделаете это в правильном порядке, вы получите фокус в неправильном окне.Рэймонд Чен (Microsoft) разместил в блоге запись об этом: Правильный порядок отключения и включения windows .
РЕДАКТИРОВАТЬ: Добавлена дополнительная информация, основанная на комментариях отasker.
Я не уверен, зачем вам созданная оболочка, чтобы настроить диалог сохранения на UserControl
.Это не элемент управления, пользователь не будет взаимодействовать с ним в вашей форме.Вы только собираетесь показать это из своего кода.Таким образом, я думаю, что лучшим вариантом было бы создать новый класс, назвать его что-то вроде SaveDialogHelper
и предоставить статический метод с именем ShowSaveDialog
или что-то в этом роде.Например:
public static class SaveDialogHelper
{
public string ShowSaveDialog(IWin32Window owner)
{
// Fill the OPENFILENAME struct, and do any necessary customizations
// ...
// Show the save dialog
// ...
// Return the path that was selected by the user
// ...
}
}
Обратите внимание, что функция ShowSaveDialog
принимает один параметр (owner
) типа IWin32Window
, так же как и метод ShowDialog
в .NET Framework.Когда вы вызываете эту функцию, просто укажите форму, которой вы хотите владеть диалоговым окном:
SaveDialogHelper.ShowSaveDialog(this);
А внутри функции вы можете извлечь дескриптор окна (hwnd
в терминологии Win32), используя Handle
свойство , и установите hwndOwner
член структуры OPENFILENAME
соответственно:
hwndOwner = owner.Handle;