Как заблокировать пользовательский интерфейс 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 сделает трюк!