Перерисовать управление внутри цикла?

Я хотел бы обновить элемент управления ProgressBar в цикле, который выполняет какой-то длительный процесс, например. что-то вроде этого для примера:

for (int p = 0; p < 100; p++)
{
   progBar.Value = p;
   // do some work here
}

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

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

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

Привяжите ProgressBar.Value к некоторому свойству класса, который реализует INotifyPropertyChanged (обычно ViewModel привязан к DataContext родительского окна/страницы), затем запустите новую задачу (Task.Run) с вашим циклом и измените связанное свойство...

Selvin 28.09.2022 11:20
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Существует только один поток пользовательского интерфейса, и его нельзя блокировать.

Таким образом, решение состоит в том, чтобы перенести трудоемкую работу в фоновый поток, например, с помощью Task.Run. Но вы не можете обновить пользовательский интерфейс непосредственно из этого фонового потока.

Чтобы обновить индикатор выполнения, вам нужно какое-то общее поле. Один из способов сделать это — использовать класс Progress, ваша фоновая работа должна вызывать OnReport, и вы должны зарегистрировать обработчик событий для ProgressChanged. Класс гарантирует, что событие возникнет в потоке пользовательского интерфейса. Я предполагаю, что это или что-то очень похожее доступно в WinUI3, но я не очень хорошо знаком с winui.

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

Ответ принят как подходящий

Ну, вы не можете делать две вещи, например запускать цикл и обновлять ProgressBar, одновременно в одном и том же потоке.

Хитрость заключается в том, чтобы выполнить цикл в фоновом потоке:

DispatcherQueue dispatcherQueue = DispatcherQueue.GetForCurrentThread();
await Task.Run(() =>
{
    for (int p = 0; p < 100; p++)
    {
        Thread.Sleep(1500); // some long-running work...
        dispatcherQueue.TryEnqueue(() => progBar.Value = p);
    }
});

Или, по крайней мере, выполните «длительный процесс» в фоновом потоке:

for (int p = 0; p < 100; p++)
{
    await Task.Run(() => Thread.Sleep(1500)); // some long-running work...
    progBar.Value = p;
}

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