0

I think i've read all the topic about async with wpf on stackoverflow but I can't seem to figure it out.

I'm trying to run Async tasks after a button press.

I'v read this thread from Gusdor; How to run and interact with an async Task from a WPF gui

and tried it but my GUI is still frozen...

All i'm trying to figure out is, how can i run multipe task async with still updating the progressbar.

        private Task ExecutionPolicyChecker()
        {
            dc.ConsoleOutput.Add("Checking Execution Policy");
            dc.ConsoleOutput.Add(PowerShellHandler.Command("Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted; Get-ExecutionPolicy;"));
            if (!dc.ConsoleOutput.Contains("Unrestricted"))
            {
                dc.ConsoleOutput.Add("ExecutionPolicy not Unrestricted!, stopping creation");
                return Task.CompletedTask;
            }
            else
            {
                dc.ConsoleOutput.Add("No restrictions there.");
                return Task.CompletedTask;
            }

        private Task InformationThread(int deployAppCount)
        {
            dc.ConsoleOutput.Add("Starting now, Please be patient..");

            if (deployAppCount != 0)
            {
                pg2.Value = deployAppCount + 1;
                pbBorder.Visibility = Visibility.Visible;
                pbStack.Visibility = Visibility.Visible;
            }

            return Task.CompletedTask;
        }

        private async Task CountToOneHundredAsync(IProgress<int> progress, CancellationToken cancellationToken, int appCount)
        {
            await InformationThread(appCount).ConfigureAwait(true);
            progress.Report(1);
            await ExecutionPolicyChecker().ConfigureAwait(false); // But this freezes my main thread and the UI..
            progress.Report(2);
            //Other functionCalls here?
            return;
        }

        private async void CreateButton_Click(object sender, RoutedEventArgs e)
        {

            try
            {
                if (Test1_Check.IsChecked ?? false) appCount++;
                if (Test2_Check.IsChecked ?? false) appCount++;
                if (Test3_Check.IsChecked ?? false) appCount++;
                if (Test4_Check.IsChecked ?? false) appCount++;
                if (Test5_Check.IsChecked ?? false) appCount++;
                if (Test6_Check.IsChecked ?? false) appCount++;

                IProgress<int> progress = new Progress<int>(count => this.pg2.Value = count);
                currentCancellationSource = new CancellationTokenSource();
                await CountToOneHundredAsync(progress, this.currentCancellationSource.Token, appCount);

            }
            catch(OperationCanceledException)
            {
                MessageBox.Show("Operation cancelled");
            }
            finally
            {
                if (appCount == appsDeployed)
                {
                    MessageBox.Show("Finished!", "Finished", MessageBoxButton.OK, MessageBoxImage.Exclamation, MessageBoxResult.OK);
                    pbBorder.Visibility = Visibility.Collapsed;
                    pbStack.Visibility = Visibility.Collapsed;


                    this.pg2.Value = 0;
                    this.currentCancellationSource.Dispose();
                    this.currentCancellationSource = null;
                }
            }

When the user presses the CreateButton I want to run InformationThread(appCount) when it's finished I want the progressbar to go to 1 then it needs to process ExecutionPolicyChecker and when finished to progressbar to 2 and so on and so on.

However when I run it now it still all runs on the main thread and blocking the UI, I guess I just don't understand it, maybe someone is willing to explain it to me or help me out?

Kind regards, Patrick

PatrickStel
  • 45
  • 1
  • 9
  • 4
    adding `async` doesn't make your program asynchronous, it still all runs on the main thread – ASh Jun 22 '23 at 15:00
  • `async` is just syntactic sugar that allows your code to call `await` to await an already executing asynchronous operation without blocking the original thread. After `await` execution resumes on the original thread. Simply adding `async` or returning a `Task.CompletedTask` doesn't make your code asynchronous. It just adds noise and overhead – Panagiotis Kanavos Jun 22 '23 at 15:05
  • 2
    There are *no* asynchronous operations in this code. All methods are actually synchronous but return a `Task` – Panagiotis Kanavos Jun 22 '23 at 15:06
  • What does `PowerShellHandler.Command` actually do? It looks like it's a blocking function. – Charlieface Jun 22 '23 at 16:08

1 Answers1

1

I guess you want to execute ExecutionPolicyChecker() on a background thread in order to keep your UI responsive during the meantime.

The easiest way to do this is to use the Task.Run API:

private async Task CountToOneHundredAsync(IProgress<int> progress, CancellationToken cancellationToken, int appCount)
{
    await InformationThread(appCount).ConfigureAwait(true);
    progress.Report(1);
    await Task.Run(ExecutionPolicyChecker).ConfigureAwait(false);
    progress.Report(2);
    return;
}

A synchronous method doesn't get asynchronous by executing it on another thread or by using the await and async keywords. InformationThread should not return a Task given its current implementation. It's truly synchronous.

You may still want to offload a synchronous method to a background thread in order to keep the UI thread responsive.

mm8
  • 163,881
  • 10
  • 57
  • 88