Home > database >  Redraw control within a loop?
Redraw control within a loop?

Time:09-28

I'd like to update a ProgressBar control within a loop that performs some lengthy process, e.g. something like this for the sake of an example:

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

But if I try this inside a method (e.g. a button click handler) the progress bar doesn't increment until the method exits, which sort of defeats the purpose of the progress bar being included in the UI.

Is there some way to get the progress bar control to repaint/redraw inside the loop so that the UI reflects its state immediately?

Maybe this is an old-fashioned approach to doing UI and there's just better ways these days? All advice appreciated.

CodePudding user response:

There is only one UI thread, and this should not be blocked.

So the solution is to move your time consuming work to a background thread, for example by using Task.Run. But you cannot update the UI directly from this background thread.

To update the progress bar you need some kind of shared field. One way to do this would be to use the Progress class, your background work should call OnReport, and you should register an eventhandler for ProgressChanged. The class will ensure the event is raised on the UI thread. I assume this, or something very similar is available in WinUI3, but I'm not very familiar with winui.

Another approach is to use a shared volatile field, and use a timer (one that ticks on the UI thread) to periodically update the progress bar from the shared field.

CodePudding user response:

Well, you can't do two things, such as running a loop and updating a ProgressBar, simultaneously on the same thread.

The trick is to execute the loop on a background thread:

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);
    }
});

Or at least do the "lengthy process" on a background thread:

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