Reputation: 115
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
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