Reputation: 4766
I have a following problem. I have a synchronous .Save() action that takes quite a few minutes to complete. I cannot make it async (3rd party library), so to keep the UI responsive, I am using it all in Task.Run()
.
I would like to report progress so that the users sees that something is happening - and I want to make it in the Status label - a simple and old school append and remove dots to string, sort of like
Wait.
Wait..
Wait...
Wait.
I don't know how to do it in a simple way - I thought of a while
loop that would break once the Task ends, but it doesn't seem to work - either the UI is blocked or the status label does not update.
I tried a couple of things, for example:
bool done = false;
Task.Run(() =>
{
Exporter.DoLongSyncTask();
}).ContinueWith(r => done = true);
StatusLabel = ".";
while (!done)
{
if (StatusLabel == "")
StatusLabel = ".";
else if (StatusLabel == ".")
StatusLabel = "..";
else if (StatusLabel == "..")
StatusLabel = "";
}
(StatusLabel is a property with INotifyPropertyChanged implemented, it works OK)
and more complicated
private async Task<bool> DoTheWork()
{
await Task.Run(() => TheFile.Save());
return true;
}
private string ReportProgress(string status)
{
if (status == ".")
status = "..";
else if (status == "..")
status = "...";
else if (status == "...")
status = ".";
MyProgress.Report(new InDesignExporterProgress { StatusInfo = status });
return status;
}
private string ReportProgress(string status)
{
if (status == ".")
status = "..";
else if (status == "..")
status = "...";
else if (status == "...")
status = ".";
MyProgress.Report(new SomeProgressClass { StatusInfo = status });
return status;
}
and the above are called from here
bool done = false;
Task.Run(() =>
{
done = DoTheWork().Result;
});
string status = ".";
while (!done)
{
status = ReportProgress(status);
}
So, what's the right way?
Upvotes: 1
Views: 12162
Reputation: 344
I think you are blocking your UI thread with the while loop since I guess it's running on that thread.
I suggest you try to change your while loop like this and the method signature to async Task
public async Task DoSomething(){
bool done = false;
Task.Run(() =>
{
Exporter.DoLongSyncTask();
}).ContinueWith(r => done = true);
StatusLabel = ".";
while (!done)
{
if (StatusLabel == "")
StatusLabel = ".";
else if (StatusLabel == ".")
StatusLabel = "..";
else if (StatusLabel == "..")
StatusLabel = "";
await Task.Delay(200);
}
}
Upvotes: 0
Reputation: 14846
To know if a task has been completed, check the value of the IsCompleted property.
while (!task.IsCompleted)
{
// ...
}
But, for what I think you're trying to, I'd do something like this:
using (var timer = new System.Windows.Forms.Timer())
{
timer.Tick += (s, e) =>
{
if (StatusLabel == "")
StatusLabel = ".";
else if (StatusLabel == ".")
StatusLabel = "..";
else if (StatusLabel == "..")
StatusLabel = "";
};
timer.Interval = 100;
timer.Enabled = true;
await Task.Run(() => Exporter.DoLongSyncTask);
}
Upvotes: 4