KushGene
KushGene

Reputation: 115

Wait until first BackgroundWorker is finished before running the second Worker

I want to make a "Checklist" of my Installation:

1st Create Table
2nd Add PrimaryKey
3rd Set AutoIncrement
4th InsertData

So I made 4 BackgroundWorkers because of using an Loading Animation for each step:

[X] Create Table (Finished)
[...] Add Primary Key (In process)
[ ] Set AutoIncrement (Didn't loaded yet)
[ ] InsertData (didn't loaded yet)

The thing is, that the Code will not wait until the First BackgroundWorker is finished before running the second one.

This is the Code I have for now:

if (result == MessageBoxResult.Yes)
{
    DialogHostLoading.IsOpen = true;
    if (worker.IsBusy)
        {
            worker.CancelAsync();
            worker.RunWorkerAsync();
            MessageBox.Show("IsBusy");
        }
        else
        {
            if(!isError)
            {
                #region CreateTable
                tableIcon.Visibility = Visibility.Collapsed;
                tableIconLoading.Visibility = Visibility.Visible;
                worker.RunWorkerAsync("CreateTable");
                #endregion

                #region SetPrimaryKey
                setPrimaryKeyIcon.Visibility = Visibility.Collapsed;
                setPrimaryKeyLoading.Visibility = Visibility.Visible;
                worker.RunWorkerAsync("SetPrimaryKey");
                #endregion

                #region SetAutoIncrement
                setAutoIncrementIcon.Visibility = Visibility.Collapsed;
                setAutoIncrementLoading.Visibility = Visibility.Visible;
                worker.RunWorkerAsync("SetAutoIncrement");
                #endregion


                // Close Dialog if finished without Errors
                DialogHostLoading.IsOpen = false;
                MessageBox.Show("Import erfolgreich.");
            }
            else
            {
                if(!string.IsNullOrEmpty(ErrorMessageString))
                {
                    MessageBox.Show(ErrorMessageString);
                    DialogHostLoading.IsOpen = false;
                    ErrorMessageString = string.Empty;
                }
                else
                {
                    Debug.WriteLine("isError = true BUT ErrorMessageString is null or empty");
                }

            }
        }

The DoWork are SQL Querys and now the RunWorkerCompleted Event:

private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if(e.Result.GetType() == typeof(string))
    {
        Color redColor = (Color)ColorConverter.ConvertFromString("#DDC31616");
        Color greenColor = (Color)ColorConverter.ConvertFromString("#DD15992D");
        switch (e.Result)
        {
            case "CreateTable":
                if(string.IsNullOrEmpty(ErrorMessageString))
                {
                    tableIcon.Foreground = new SolidColorBrush(redColor);
                    tableIcon.Kind = MaterialDesignThemes.Wpf.PackIconKind.CloseCircle;
                    tableIconLoading.Visibility = Visibility.Collapsed;
                    tableIcon.Visibility = Visibility.Visible;
                    isError = true;
                }
                else
                {
                    tableIcon.Foreground = new SolidColorBrush(greenColor);
                    tableIcon.Kind = MaterialDesignThemes.Wpf.PackIconKind.CheckCircle;
                    tableIconLoading.Visibility = Visibility.Collapsed;
                    tableIcon.Visibility = Visibility.Visible;
                }
                break;
            case "SetPrimaryKey":
                if(string.IsNullOrEmpty(ErrorMessageString))
                {
                    setPrimaryKeyIcon.Foreground = new SolidColorBrush(redColor);
                    setPrimaryKeyIcon.Kind = MaterialDesignThemes.Wpf.PackIconKind.CloseCircle;
                    setPrimaryKeyLoading.Visibility = Visibility.Collapsed;
                    setPrimaryKeyIcon.Visibility = Visibility.Visible;
                    isError = true;
                }
                else
                {
                    setPrimaryKeyIcon.Foreground = new SolidColorBrush(greenColor);
                    setPrimaryKeyIcon.Kind = MaterialDesignThemes.Wpf.PackIconKind.CheckCircle;
                    setPrimaryKeyLoading.Visibility = Visibility.Collapsed;
                    setPrimaryKeyIcon.Visibility = Visibility.Visible;
                }
                break;
        }
    }
}

What I tried is using async Tasks from another solution which doesn't worked for me:

private readonly Task _CreateTable;
public MainWindow()
{
    InitializeComponent();
    _CreateTable = PerformCreateTableAsync();
}
private async Task PerformCreateTableAsync()
    {
        await Task.Run(() =>
        {
            Thread.Sleep(TimeSpan.FromSeconds(5));
        });
    }

    private async void CreateTable()
    {
        Color redColor = (Color)ColorConverter.ConvertFromString("#DDC31616");
        Color greenColor = (Color)ColorConverter.ConvertFromString("#DD15992D");

        tableIcon.Visibility = Visibility.Collapsed;
        tableIconLoading.Visibility = Visibility.Visible;

        await _CreateTable;

        tableIcon.Foreground = new SolidColorBrush(greenColor);
        tableIcon.Kind = MaterialDesignThemes.Wpf.PackIconKind.CheckCircle;
        tableIconLoading.Visibility = Visibility.Collapsed;
        tableIcon.Visibility = Visibility.Visible;
    }

and where I now calling the RunWorkerAsync I called the Task via:

#region CreateTable
CreateTable();
#endregion

Upvotes: 0

Views: 90

Answers (1)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131219

BackgroundWorker is obsolete. All its functionality and much more is available through tasks, async/await and the IProgress< T> interface. In fact, composability is one of BGW's greatest weaknesses.

Using async/await is actually a lot easier than using BGW. If you wanted to execute an operation in response to eg a button click you could write this:

private async Task CreateTableAsync(string tableName)
{
    //Execute SQL code that creates a table
    using(var connection=new SqlConnection(_connString)
    using(var cmd=new SqlCommand(connection,sql))
    {
        ....
        await cmd.ExecuteNonQueryAsync();
    }
}

private async void MyButton_Click(object sender, EventArgs args)
{
    Color redColor = (Color)ColorConverter.ConvertFromString("#DDC31616");
    Color greenColor = (Color)ColorConverter.ConvertFromString("#DD15992D");

    tableIcon.Visibility = Visibility.Collapsed;
    tableIconLoading.Visibility = Visibility.Visible;

    try 
    {
        await CreateTableAsync("SomeTableName");

        tableIcon.Foreground = new SolidColorBrush(greenColor);
        tableIcon.Kind = MaterialDesignThemes.Wpf.PackIconKind.CheckCircle;
        tableIconLoading.Visibility = Visibility.Collapsed;
        tableIcon.Visibility = Visibility.Visible;
    }
    catch(Exception exc)
    {
        MessageBox.Show(exc.ToString(),"Ouch!");
    }
}

Note that async void should only be used for event handlers. All other methods should return async Task or async Task<T>. async void methods can't be awaited. They are essentially fire-and-forget methods.

If you want to combine multiple async call, the only thing you need to do is add them one after the other :

private async void MyButton_Click(object sender, EventArgs args)
{
    SetWorkingModeUI();
    try 
    {
        await CreateTableAsync("SomeTableName");
        await CreateTableAsync("OtherTableName");
        await CreateTableAsync("ThirdTableName");

        SetIdleModeUI();
    }
    catch(Exception exc)
    {
        SomeProperErrorHandlerAndLogger(exc);
    }
}

You can even run multiple operations in parallel and await all of them to complete :

private async void MyButton_Click(object sender, EventArgs args)
{
    SetWorkingModeUI();
    try 
    {
        var tasks = new[] {
                   AsyncCall1(),
                   AsyncCall2(),
                   AsyncCall3()
        };
        await Task.WhenAll(tasks);

        SetIdleModeUI();
    }
    catch(Exception exc)
    {
        SomeProperErrorHandlerAndLogger(exc);
    }
}

Upvotes: 1

Related Questions