1

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.

PathWalker
  • 17
  • 4
  • For progress reporting use `Progress`/`IProgress` – canton7 Jul 08 '21 at 16:19
  • 2
    The whole point of async/await is to not have to deal with callbacks. If you want to execute code after some async operation has completed, all you have to do is **put that code after the `await `.** See duplicate for more details on how to transition from `BackgroundWorker` to async/await code. – Peter Duniho Jul 08 '21 at 17:10
  • 2
    [Avoid async void](https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void). It is intended for event handlers only, so the only valid place in your code for async void is the `private void btn_comercialInstall_Click` event handler. The question [currently marked as duplicate](https://stackoverflow.com/questions/12414601) is not a direct duplicate of your question (that question is about *when*, while this one is about *how*), so if you don't find a solution to your problem there tell me to cast a reopen vote. – Theodor Zoulias Jul 08 '21 at 18:58
  • 2
    https://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-round-1.html – Stephen Cleary Jul 08 '21 at 22:57
  • While that question is not exactly a duplicate, some of the awnsers and comments there really did help me so I think it's fine for this to say marked as a duplicate. – PathWalker Jul 09 '21 at 17:34
  • Should I edit the question with the things I understood now or leave it be? – PathWalker Jul 09 '21 at 17:47
  • No, including an answer inside the body of a question is frowned upon here. If you think that you've learned something that is worth sharing with others who may struggle with a similar problem, you should post it as an answer. Answering your own question OK, it is actually [encouraged](https://stackoverflow.com/help/self-answer) here. You could either post a new question, or ask to reopen this question (this may take time though). – Theodor Zoulias Jul 10 '21 at 11:17

0 Answers0