Как заблокировать пользовательский интерфейс Winforms, когда фоновый поток запущен

Я унаследовал приложение Winforms, которое выполняет много длительных вызовов на сервер приложений из потока пользовательского интерфейса, поэтому пользовательский интерфейс остается невосприимчивым, непригодным к использованию, незаменимым в течение некоторого времени. (Что заставляет меня действительно пойти AAAAAAAAARGH!)

Я планирую переместить вызовы сервера в фоновый поток и отключить пользовательский интерфейс, но перемещать и закрывать - в то время как фоновый поток выполняет свою работу.

Итак, что было бы лучшим способом запретить ввод пользователя в мое приложение? Я размышляю о "модальном диалоге прогресса", но я бы предпочел решение, которое не заставило меня бросать визуальные изображения в лицо пользователю (некоторые серверные операции выполняются менее чем за 500 мс, поэтому диалог не является оптимальным...)

Есть ли какой-либо способ в Winforms, чтобы пользователь не запускал действия или не изменял данные в приложении, а пропускал несколько избранных вещей (изменение размера, отображение, скрытие и семейство и закрытие окна пользователем)? Я бы предпочел способ, который не заставляет меня обращаться к каждому элементу пользовательского интерфейса в моих формах и устанавливать его на отключенный... их довольно много, и это приложение действительно "взломано в дизайнере пользовательского интерфейса", пока оно не покажет яркие вещи "стиль исходного кода. Никакой способ рефакторинга КАЖДОГО вонючего до даты выпуска...

О, кстати, это приложение живет в .net framework 2

Ответ 1

Единственный способ, которым я знаю, - отключить некоторые/все элементы управления. Однако в зависимости от того, как выкладываются элементы управления, нет необходимости устанавливать каждый элемент управления как отключенный - когда элемент управления контейнера отключен, то все его дети также отключены. Например, если у вас есть GroupBox с некоторыми элементами управления, если вы отключили GroupBox, тогда все элементы управления в GroupBox тоже будут отключены.

Ответ 2

Выберите элемент управления контейнера верхнего уровня (может быть самой формой) и установите для свойства Enabled значение false. Все элементы управления, расположенные на этом элементе управления, будут отключены, что предотвратит их получение.

Ответ 3

Проблема с простым включением/отключением кнопок заключается в том, что события пользовательского интерфейса все равно будут добавлены в сообщение, пока задача будет запущена.

Скажите, что у вас есть кнопка поиска и кнопка Reset. Когда вы нажимаете "Поиск", вы отключите обе кнопки. Поиск выполняется некоторое время. Если пользователь нажимает Reset, даже если он отключен, поиск будет Reset сразу после завершения.

Быстрый и грязный способ сделать это:

Application.DoEvents();

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

Ответ 4

На уровне API Win32 существует функция EnableWindow, вы можете отключить любую ручку окна (вам нужно получить базовый дескриптор вашего главное окно, конечно, и любых других окон верхнего уровня). Тем не менее, я не тестировал его в WinForms. (Я уверен, что есть другие ответы на уровне User32, но я не могу вспомнить API-запросы прямо сейчас.)

Примечание. Это не делает серые элементы управления, что снижает его полезность с точки зрения удобства использования (пользователь просто видит "замороженное приложение" ). Он становится немного лучше, если вы по крайней мере установите курсор песочных часов.

Однако это быстрый и грязный способ работы с асинхронной обработкой. Вам действительно нужно заблокировать пользователя из всего приложения? Возможно, это всего лишь несколько функций, которые должны быть запрещены во время выполнения запроса?

Ответ 5

К сожалению, с помощью WinForms вам, вероятно, придется отключить/включить кнопки одним общим методом. Это одно из преимуществ, которое WPF приносит в виде окон - гораздо проще справляться с этими ситуациями.

Что касается не блокирования вашего пользовательского интерфейса, вам нужно будет перевести свои вызовы на асинхронную модель программирования. В вашем случае я бы рекомендовал взглянуть на ThreadPool.

Вы хотите сделать что-то вроде кнопки, которая отключает ваши элементы управления, вызывать вашу операцию в пуле потоков, а затем повторно использовать их при завершении.

Ответ 6

Я отвечаю на старый поток здесь, но я увидел этот вопрос и вспомнил старое приложение WinForm, где у меня была такая же проблема с отключением формы, но все же позволяла изменять ее размер и перемещать и т.д. Я загрузил мои и нашел решение:

  • Поместите элемент управления Panel в форму и дайте свойству Dock значение DockStyle.Fill.
  • Вместо того, чтобы помещать все элементы формы верхнего уровня непосредственно в форму, поместите их в элемент управления Panel.
  • Теперь для магического бита - когда вы хотите отключить элементы управления формой, просто установите для свойства Panel Enabled значение false. Когда вы это сделаете, все элементы управления, содержащиеся в элементе управления Panel, также будут отключены, но сама форма по-прежнему включена и, следовательно, изменена и т.д. Чтобы восстановить состояние всех элементов управления, просто верните свойство Enabled в значение true.

Строго говоря, вам не нужно использовать элемент управления Panel, любой элемент управления контейнером должен демонстрировать такое же поведение. Даже элемент управления PictureBox сделает трюк!