У меня есть приложение Windows Forms с главным окном и 0 или более других открытых окон. Другие открытые окна не принадлежат главному окну и не являются модальными диалоговыми окнами или чем-то еще. Тем не менее, поведение по умолчанию - если главное окно закрывается, то приложение закрывается из-за возврата метода Application.Run
. Это нормально, но поскольку у пользователя может быть несохраненная работа в других открытых окнах, я реализовал некоторую логику закрытия форм.
Когда другое окно закрывается, оно проверяет несохраненные изменения и предлагает пользователю стандартную подсказку в стиле «Сохранить / Не сохранять / Отменить» в Microsoft Word.
Когда главное окно закрывается, оно пытается сначала закрыть все остальные открытые окна. Если какой-либо из них не удается закрыть (т. Е. Пользователь нажал кнопку Отмена), он останавливает событие закрытия.
Эта логика встречается в событиях FormClosing и прекрасно работает, за исключением случаев, когда пользователь использует команду панели задач «Закрыть все окна». Это появляется в новой панели задач 7, а также в XP / Vista, когда группировка активна (хотя тогда она помечена как «Закрыть группу»).
Эта команда, похоже, отправляет сообщение о закрытии всем окнам. Проблема заключается в том, что каждое другое окно проверяет наличие изменений и подсказок, а затем основное окно пытается закрыть другие окна. Если я запрашиваю пользователя с помощью стандартной команды MessageBox.Show, то событие закрытия приостанавливается, пока диалоговое окно ожидает ответа пользователя. После нажатия кнопки она обрабатывается как обычно, но все остальные окна либо игнорируют, либо игнорируют команду закрытия окна. И не важно, на что они нажали. Форма, отображающая подсказку, реагирует правильно (если они нажимают кнопку Отмена, она остается открытой, если нет, она закрывается нормально). Но все остальные окна, включая основной акт, как будто ничего не случилось. Их событие FormClosing никогда не возникает.
Если я использую TaskDialog (посредством вызова неуправляемого TaskDialogIndirect ), то в тот момент, когда должно появиться приглашение и приостановить событие закрытия формы, вместо этого другие формы обрабатывают свои события закрытия формы. Это на том же потоке не меньше (основной поток пользовательского интерфейса). Когда наступает очередь главного окна, оно пытается закрыть все формы, как обычно. Любая форма, которая попыталась получить приглашение, все еще открыта, остальные с тех пор закрылись сами по себе из-за команды «Закрыть все окна». Главное окно пытается закрыть все еще оставшиеся, в результате чего обрабатывается второе событие FormClosing и вторая попытка запросить (в конце концов, изменения все еще не сохранены!) Все в главном потоке.
Конечным результатом является то, что подсказка появляется дважды подряд после разматывания через стек вызовов. Я знаю, что все это происходит в одном потоке через стек вызовов Visual Studio. Я могу оглянуться назад в любой момент до первой попытки запроса до того момента, когда он собирается вызвать его снова. Кажется, только второй вызов действительно обрабатывает его и показывает подсказку. Первый раз через это почти как где-то в неуправляемом коде, который он уступает другим сообщениям. Я должен упомянуть заранее, что я нигде не вызываю Application.DoEvents.
Является ли TaskDialogIndirect своего рода полусинхронным вызовом? Но я никогда не оставляю основной поток через все это, насколько я могу судить. И тогда почему стандартный MessageBox немедленно запрашивает (как я думаю, что TaskDialog тоже должен), но затем появляется, чтобы отбросить все другие события закрытия окна? Возможно, другие сообщения о закрытии окна просто истекают? Разве они не должны находиться в очереди сообщений, пока не вернется модальное диалоговое окно (окно сообщения)?
У меня такое ощущение, что это все из-за природы управляемой оболочки для Win32 API в Windows Forms & mdash; дырявая абстракция возможно.