I have been trying to learn and use await/async
instead of backgroundworker
I managed to get most of the things I was used to use a backgroundworker
for running, but RunWorkerCompleted
is something I couldn't recreate. The behaviour being, similar to Fire and Forget
in a way the flow being
The Goal:
Having a method InstallSoftware(int code)
Start InstallSoftware(1)
> main thread is free to do anything including creating/running InstallSoftware(2)
and or InstallSoftware(3)
> InstallSoftware(1)
finishes it's run and calls the main thread to update the UI with success or failure.
Being more specific of my current situation, I have a WPF software that is basically a custom installer/updater, it handles the instalation and updates of 3 different other softwares. I want the user to be able to click to install or update all 3 at the same time if so desired, each in a different thread.
My code:
private void btn_comercialInstall_Click(object sender, RoutedEventArgs e)
{
InstallSoftware(2);
}
// All 3 buttons are the exact same just changing the code
private void InstallSoftware(int code)
{
try
{
Task<bool> download;
switch (code)
{
case 1:
download = Core.DownloadFiles(7);
InstallMoveFiles(prg_frotaUpdate, "", programFiles + "installLocation", download);
break;
// Same as the buttons, theres 3 cases, only changes being the codes and Progress Bars attached
default:
break;
}
}
catch (Exception e)
{
// Error Handling
}
}
private async void InstallMoveFiles(ProgressBar bar, string zipPath, string savePath, Task<bool> download)
{
string filePath = "<pathBeingHandledByAnotherMethod>";
string tempPath = savePath;
string zipName = "<pathBeingHandledByAnotherMethod>";
bar.Value = 1;
Directory.Delete(filePath, true);
Directory.CreateDirectory(filePath);
bar.Value = 10;
_ = await download; // Currently discarting the return, will later implement error handling with the bool that is returned
using (ZipFile zip = ZipFile.Read(tempPath + "/" + zipName))
{
foreach (ZipEntry e in zip)
{
e.Extract(filePath);
}
}
bar.Value = 30;
//copy files
bar.Value = 50;
//clean download folder
bar.Value = 70;
//set version folder
bar.Value = 100;
InitProcedures();
}
The issue:
When download = Core.DownloadFiles(7);
is called, everything in the main thread freezes and resumes only when _ = await download;
is done. I suppose that it is the software going though the previous steps quickly and then freezes the main thread waiting for the download to finish. If I add a MessageBox
between those two, all the UI changes get updated when the MessageBox
is shown, but if theres nothing, even the ones that happen before the await
only get updated after the await
is done
My Ideas:
I imagine that making InstallMoveFiles
itself being a Task
and Fire and Forget
it, and not use the ProgressBar
instance there and figure out another way to report progress, but I cannot see how I would make it call back to the main thread like that to inform that the instalation has been sucessful or if theres errors, and then update the UI.
Things I've been reading:
Been doing research on the matter as I'm a newbie when it comes to WPF or await/async
I googled and read these which helped me getting to this point, but not how to recreate the behaviour I was used to with backgroundworker
.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
https://www.pluralsight.com/guides/returning-void-from-c-async-method
https://www.pluralsight.com/guides/understand-control-flow-async-await blocking main thread on async/await https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/start-multiple-async-tasks-and-process-them-as-they-complete There was more, but these are the tabs I still have open/that felt like got me closer to my goal.
Extra Notes:
I'm actively trying to improve my questions and bring some value, so if it's a bad question please do tell me why. And if it is a duplicate, if you have the time,maybe some tips on how can I improve my research, because I just spent my last 4-5 hours reading and testing code about this with not much success. On another adendum, is it good for me edit my question to include the solutions people give in the comments?
I have the suspicion that I'm misunderstanding some concept of how await/async
works, but couldn't figure out what, yet.