Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass different method/function to DoWork event of Background worker

Please bear with my ignorance on this subject and on the terminology I have used. Please correct me where I am incorrect.

I have used a background Worker from the toolbox onto my form and I am passing a method to the DoWork event. What I have understood in this first attempt with background Worker is that I can use the background Worker that I've created only for 1 task. See code below:

private void btn1_Click(object sender, EventArgs e)
{
   // Should call the uploadToDB1 using BackgroundWorker's DoWork event.
     backgroundWorker1.RunWorkerAsync();
}

private void btn2_Click(object sender, EventArgs e)
{
    // Should call the uploadToDB2 using BackgroundWorker's DoWork event.
    backgroundWorker1.RunWorkerAsync();
}

private void uploadToDB1()
{
    // Code for uploading to DB 1.
}        

private void uploadToDB2()
{
    // Code for uploading to DB 2.
}  

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {

        uploadToDB1(); // I want to change this to uploadToDB2 i.e. a variable method, How do I assign a call to this?

    }
    catch (Exception ex)
    {

        MessageBox.Show(ex.Message);
    }

}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Visible = true;
    progressBar1.Maximum = maxRecords;
    lblProgress.Text = Convert.ToString(e.ProgressPercentage.ToString() + "/" + maxRecords);
    progressBar1.Value = e.ProgressPercentage;

}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    progressBar1.Visible = false;
    lblProgress.Text = "";
}

I need to be able to dynamically pass a method to the DoWork event without having the need to create multiple background Workers as the actions in the rest of the events related to the background Worker remains unchanged.

Could you please advise how I should go about doing this?

Updated Code using TPL, however I am getting a cross thread error. Could you please help with a corrected code? Upload to DB 2 should happen only after upload to DB 1 is complete. So each time an upload happens the label and progress bar needs to be updated. I also need to pass different text to the label.

private void btn1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(uploadToDB1);
}
private void uploadToDB1()
{
    for(i=0;i<dt.rows.count-1;i++)
    {
        // Code for inserting into DB1.

        progressbar1.maximum=dt.rows.count-1;
        progressbar1.value=i;
    }
    uploadToDB2();

}

private void uploadToDB2()
{
    for(i=0;i<dt.rows.count-1;i++)
    {
        // Code for inserting into DB2.

        progressbar1.maximum=dt.rows.count-1;
        progressbar1.value=i;
    }

}
like image 830
svb Avatar asked Nov 10 '22 15:11

svb


1 Answers

What you can do, and is a bit of a hack, is pass an Action as an argument for invocation to your DoWorkAsync:

var bw = new BackgroundWorker();
bw.DoWork += (s, o) => 
{
    Action actualWork = (Action)o.Argument;
    actualWork();
}

and when you invoke DoWorkAsync:

Action action = () => DoSomething();
bw.RunWorkerAsync(action);

Instead, as @Sriram suggested, look into the Task Parallel Library, which will make you life a bit easier:

private async void btn1_Click(object sender, EventArgs e)
{
    await Task.Run(UpdateFirst);
    // Update UI here.
}

private async void btn2_Click(object sender, EventArgs e)
{
    await Task.Run(UpdateSecond);
    // Update UI again.
}

An extensive answer on TPL and the use of IProgess<T> can be found in How to provide a feedback to UI in a async method?

like image 119
Yuval Itzchakov Avatar answered Nov 15 '22 07:11

Yuval Itzchakov