Aaron Thomas
Aaron Thomas

Reputation: 5281

Looping while performing work without blocking UI

The built-in progress reporter allows for a UI element to be updated, while also running on the thread pool (ref here). This is perfect for occasional updates to a UI element, and all examples I've found showcase that scenario.

However, I need to continuously update a WPF UI element while the CPU-bound work is running, so that it 'loops' through a message in this way until the work is finished:

Running
Running.
Running..
Running...
Running

How can this be accomplished without blocking the UI thread?

Here's the current implementation:

internal async Task<bool> FireWithStatusAndWork(IProgress<string> progress) {
    var reportedProgress = "Running";

    bool continueReporting = true;
    bool workStarted = false;

    // loop through the message, but also do background work
    while (continueReporting) {
        if (!workStarted) {
            workStarted = true;
            await Task.Run(() => { model.CPUIntensiveWork(); }).ConfigureAwait(false);
            continueReporting = false;
        }
        progress.Report(reportedProgress);
        if (reportedProgress.Length < 10) reportedProgress += "."; else reportedProgress = "Running";
        Thread.Sleep(200);
    }
    return true;
}

I apologize for yet another async newbie question, but I'm trying to learn from both a philosophical standpoint (proper use for some scenarios but not for others) as well as a practical one (just get the thing running).

I have looked through MS docs for TAP... but if I've missed something pertinent I would be grateful if that were provided as a learning point.

Upvotes: 0

Views: 1167

Answers (1)

Camilo Terevinto
Camilo Terevinto

Reputation: 32058

Your loop will only ever run once, given that you are awaiting the Task. Rather than waiting for the task to complete at once, you should create the task and check for its status periodically.

Something like this should work:

internal async Task<bool> FireWithStatusAndWork(IProgress<string> progress) 
{
    var reportedProgress = "Running";

    var task = Task.Run(() => model.CPUIntensiveWork());

    while (!task.IsCompleted)
    {
        progress.Report(reportedProgress);

        if (reportedProgress.Length < 10) 
        {
            reportedProgress += "."; 
        }
        else 
        {
            reportedProgress = "Running";        
        }

        await Task.Delay(200);
    }

    return true;
}

Upvotes: 2

Related Questions