Проблема заключается в том, что при вызове ShowDialog
ваш основной поток пользовательского интерфейса прекратит отправку сообщений. Посмотрите на этом упрощенном цикле сообщений:
while(true)
{
Message m;
GetMessage(out m);
// if close button pressed etc.
if (m.Msg == WM_QUIT) break;
DispatchMessage(m);
}
При активации вашего диалога, это выполняется в DispatchMessage и начинает новый цикл обработки сообщений, который подобен. Из-за этого нового цикла цикл из вашего главного окна блокируется при вызове DispatchMessage и не будет обрабатывать любые сообщения клавиатуры. Это сложная работа с несколькими контурами пользовательского интерфейса, и по этой причине я бы рекомендовал использовать регулярное сообщение Show()
(которое не будет блокировать ваш основной цикл приложения) и найти другой способ настроить ориентацию пользователей на это окно.
Существует вызов ap/invoke, который я использовал в прошлом, который устанавливает родительское окно как отключенное и направляет фокус пользователя на дочернее окно, он почти идентичен поведению вызова ShowDialog
, но без блокировки потока , То, что вы сделали бы, это установить владельца вашей дочерней формы, вызвать обычный метод Show()
и, наконец, установить включенное состояние родительского окна в значение false. Вы можете сделать позже с этим кодом:
const int GWL_STYLE = -16;
const int WS_DISABLED = 0x08000000;
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
void SetWindowEnabled(Form form, bool enabled)
{
SetWindowLong(form.Handle, GWL_STYLE, GetWindowLong(form.Handle, GWL_STYLE) &
~WS_DISABLED | (enabled ? 0 : WS_DISABLED));
}
Касание на ваш комментарий о сложенных модели окон, я думаю, что это возможно, но это очень важно, чтобы убедиться, что нативный метод вызывается повторно включить родительское окно когда диалог закрыт.Я хотел бы реализовать метод расширения, который выглядит примерно так:
public static class FormsExtensions
{
public static Task<bool> ShowNativeDialog(this Form child, Form owner)
{
var tcs = new TaskCompletionSource<bool>();
child.Show();
SetWindowEnabled(owner, false);
child.Closed += (sender, args) => {
SetWindowEnabled(owner, true);
tcs.SetResult(true);
}
return tcs.Task;
}
}
А использование будет выглядеть примерно так:
DialogForm dialog = new DialogForm();
await dialog.ShowNativeDialog(this);
Используя Await, вы можете остановить поток выполнения без блокировки цикла UI сообщений ,
Мне нравится этот ответ, я даже не думал о предварительной обработке wndproc. Я думаю, у op есть два хороших варианта: – caesay
@caesay - да, у меня есть :) Я уже видел эту концепцию, но я думал, что ее область действия - это форма, а не приложение. Он также позволяет обрабатывать все другие типы сообщений, что может быть полезно. – miroxlav
@miroxlav: дайте нам знать, с каким способом вы пошли в конце. – caesay