Невозможно включить отключенный элемент управления в том же блоке

У меня есть следующий код. В том же блоке кода я отключаю элемент управления, затем включаю его, но он, похоже, не работает и остается в исходном состоянии IsEnable.

// Button never enable
public void Foo()
{
   button1.IsEnabled = false
   Thread.Sleep(3000);
   button1.IsEnabled = true;
   Thread.Sleep(3000);
   button1.IsEnabled = false;
}

4 ответа

Решение

Прежде всего: не странно, что кнопка не активируется после Foo Метод завершен, так как последняя строка отключает кнопку.

Если вы хотите "увидеть" изменение состояния включенной кнопки, вам нужно обработать оконные сообщения перед сном. Thread.Sleep приводит к тому, что поток пользовательского интерфейса переходит в спящий режим, поэтому обновления пользовательского интерфейса не будут. Что вам нужно сделать, это заставить приложение обрабатывать все ожидающие сообщения окна.

public static void DoEvents()
{
    if (Application.Current != null)
        Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
}

public void Foo()
{
   button1.IsEnabled = false
   DoEvents();
   Thread.Sleep(3000);

   button1.IsEnabled = true;
   DoEvents();
   Thread.Sleep(3000);

   button1.IsEnabled = false;
}

РЕДАКТИРОВАТЬ
Дальнейшее объяснение:

Когда первый Thread.Sleep вызывается, кнопка отключена (IsEnabled является false). Затем, подождав 3 секунды, вы устанавливаете кнопку в положение "включено", а после этого снова отключаете ее. Кнопка фактически находится в этом состоянии, но визуальной обратной связи нет (например, если вы посмотрите на форму, вы не увидите кнопку "мигать").

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

Поэтому вам нужно дать окну возможность получать сообщения и обновлять его дочерние элементы. В приложениях Windows Forms это было сделано с Application.DoEvents, который обработал все ожидающие сообщения окна.

В WPF нет такого понятия, как Application.DoEvents, но код, который я разместил, имитирует это, Thread это ничего не делает - но этого небольшого промежутка времени между изменением включенного состояния кнопки и блокировкой потока пользовательского интерфейса достаточно для перекрашивания элемента управления кнопки.

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

Вы должны запустить свой код в другом потоке с помощью диспетчера.

Вы когда-нибудь думали, что вы можете быть в UI-Thread? Читайте о диспетчере в wpf.

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

NET предоставляет несколько вариантов потоков, таких как BackgroundWorker, Thread, ThreadPool и т. Д.

Более новая платформа NET также предоставляет метод async/await, позволяющий потоку GUI выполнять другую работу во время события.

Другие вопросы по тегам