Jevon Jevon - 27 days ago 15
C# Question

Background worker attempt

This is how the function was originally:

void fillLiguanea()
{
items = new List<string>();
this.liguanea_Lane2TableAdapter.Fill(this.pharmaciesDataSet3.Liguanea_Lane2);
try
{

string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
SqlConnection con = new SqlConnection(connectionString);
con.Open();
string query = "SELECT * FROM dbo.Liguanea_Lane2";
SqlCommand cmd = new SqlCommand(query, con);

SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
string scode = dr.GetString(dr.GetOrdinal("code"));
comboBox2.Items.Add(scode);

}
}
catch (Exception ex)
{

MessageBox.Show(ex.ToString());
}
}


This is how it looks now taking into consideration background worker:

private List <string> items;
void fillLiguanea()
{
items = new List<string>();
this.liguanea_Lane2TableAdapter.Fill(this.pharmaciesDataSet3.Liguanea_Lane2);
try
{

string connectionString = "Data Source=LPMSW09000012JD\\SQLEXPRESS;Initial Catalog=Pharmacies;Integrated Security=True";
SqlConnection con = new SqlConnection(connectionString);
con.Open();
string query = "SELECT * FROM dbo.Liguanea_Lane2";
SqlCommand cmd = new SqlCommand(query, con);

SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
string scode = dr.GetString(dr.GetOrdinal("code"));
// comboBox2.Items.Add(scode);
items.Add(scode);
}
}
catch (Exception ex)
{

MessageBox.Show(ex.ToString());
}
}


Below are my background worker functions which have been edited to populate the comboBox in question, which is comboBox2.
This is my back ground worker:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
fillLiguanea();
}


This is my RunWorkerCOmpleted:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{

if (comboBox4.SelectedIndex == 0)
{


foreach (var item in items)
{
comboBox2.Items.Add(item);
}
}
}


My question is where am I going wrong? what the code should do is populate comboBox2 from my database based on the selection of combox4's index. Currently nothing happens. Where am I going wrong?

Answer

When using BackgroundWorker you can consider such pattern:

  1. Handle DoWork event and call the time-consuming task there.
    Keep in mind the event is raised in another thread different than UI thread, so if for any reason you want to do some UI code in the event you should use Invoke to make a thread safe call to a UI element.
    Putting time-consuming UI tasks in the DoWork is useless. Because the task should be run in UI thread using Invoke and it will make the UI thread busy again.

  2. You can handle RunWorkerCompleted event to perform some tasks after the work in DoWork got completed. For example after you load data in DoWork, you can use the loaded data in RunWorkerCompleted to fill a ComboBox.

  3. You should call RunWorkerAsync method of the component to start processing DoWork event.
    ○ When an async task is running using an instance of the component you can not start another task using the same component, so to prevent exception you should check this.backgroundWorker1.IsBusy and if the component is not busy call the method.

  4. The component has a good support for error reporting or progress changing or cancelling the execution. To learn more about the features, take a look at documentations.

  5. For .NET 4.5 and later, you can use async/await pattern to perform asynchronous tasks.

Example

I suppose you have a LoadData method currently:

public void LoadData()
{
    this.categoryTableAdapter.Fill(this.testDBDataSet.Category);
}

And you want to populate a control with data which you load using LoadData. So you can handle the DoWork and RunWorkerCompleted like this:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    LoadData();
}

private void backgroundWorker1_RunWorkerCompleted(object sender, 
    RunWorkerCompletedEventArgs e)
{
    this.comboBox1.DataSource = this.testDBDataSet.Category;
    this.comboBox1.DisplayMember = "Name";
}

Also you should call the RunWorkerAsync when you want the task get started, for example:

private void button1_Click(object sender, EventArgs e)
{
    if (!this.backgroundWorker1.IsBusy)
        this.backgroundWorker1.RunWorkerAsync();
}
Comments