Принудительно перерисовать перед длительными операциями

Когда у вас есть кнопка, и вы делаете что-то вроде:

Private Function Button_OnClick

    Button.Enabled = False

    [LONG OPERATION] 

End Function

Тогда кнопка не будет серой, потому что длительная операция не позволяет потоку пользовательского интерфейса перерисовать элемент управления. Я знаю, что правильная конструкция - запуск фонового потока / диспетчера, но иногда это слишком сложно для простой операции.

Итак, как мне заставить кнопку перерисовываться в отключенном состоянии? Я попробовал .UpdateLayout () на кнопке, но это не дало никаких результатов. Я также попробовал System.Windows.Forms.DoEvents (), который обычно работает при использовании WinForms, но также не дал никакого эффекта.


person Muis    schedule 14.11.2011    source источник


Ответы (3)


Следующий код сделает то, что вы ищете. Однако я бы не стал его использовать. Для длительных операций используйте класс BackgroundWorker. Он прост в использовании и очень стабилен.
Вот код:

   public static void ProcessUITasks() {            
        DispatcherFrame frame = new DispatcherFrame();
        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate(object parameter) {
            frame.Continue = false;
            return null;
        }), null);
        Dispatcher.PushFrame(frame);
    }

Здесь вы найдете пример использования BackgroundWorker .

person HCL    schedule 14.11.2011
comment
Он довольно четко понимал, что знал о диспетчере / фоновом работнике, но не использовал его :) - person edvaldig; 15.11.2011
comment
@edvaldig: Я подчеркнул, что не использовать его, однако дал ему код, который он искал. Я не думаю, что это стоит вам -1. Если мой код не работает, дайте мне -1, но не за дополнительные советы. Я не думаю, что это честно. - person HCL; 15.11.2011
comment
Вы правы, я поспешил, прокомментируйте, чтобы компенсировать это :) - person edvaldig; 15.11.2011
comment
Как вы используете поток BackgroundWorker, если хотите открыть другое приложение через COM (что, я думаю, должно быть сделано в потоке пользовательского интерфейса / квартире STA)? - person Eric Ouellet; 01.02.2014

InvalidateVisual (); @HCL прав ... не делайте этого

Как вы говорите, лучше начать использовать фоновый поток / диспетчер и оставить поток пользовательского интерфейса разблокированным. Рассмотрите возможность использования библиотеки Reactive Extensions от Microsoft для высокоуровневого асинхронного программирования пользовательского интерфейса.

person edvaldig    schedule 14.11.2011
comment
Так не пойдет. Аннулирование делает только недействительной перекрашиваемую область. Однако это не картина. - person HCL; 15.11.2011
comment
@HCL, у меня отлично работает, см. Документацию для функции: делает недействительным рендеринг элемента и заставляет полностью пройти новый макет. OnRender вызывается после завершения цикла макета. - person edvaldig; 15.11.2011
comment
Вы уверены, что ваш UI-поток заблокирован? Последний раз тестировал под .net3.5SP1. На данный момент это не сработало. Если это работает сейчас, они, должно быть, изменили поведение с 4.0. Однако для меня это было бы большим сюрпризом. - person HCL; 15.11.2011
comment
Решает ли реактивное решение проблему длительной работы с COM, которая должна выполняться в потоке пользовательского интерфейса (квартира STA)? - person Eric Ouellet; 01.02.2014

В Windows.Forms вы можете Button.Refresh().

В Windows.Forms или WPF вы можете уступить насосу сообщений, чтобы он перерисовался. Async / Await были разработаны, чтобы позволить вам делать это без неприятного ответа HCL.

Private Async Function Button_OnClick

    Button.Enabled = False

    Await Task.Yield

    [LONG OPERATION] 

End Function
person David Jeske    schedule 10.06.2017