Jevon Jevon - 25 days ago 14
C# Question

Background Worker implementation

This is my background work DoWor function, is the implementation taking into consideration the GUI operation done okay?

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
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.Invoke((MethodInvoker)delegate
{
comboBox2.Items.Add(scode);
});
}
}
catch (Exception ex)
{

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


And this is the function that calls it:

private void comboBox4_SelectedIndexChanged(object sender, EventArgs e)
{
if(comboBox4.SelectedIndex == 0)
{
backgroundWorker1.RunWorkerAsync();

}
else
{

MessageBox.Show("This table doesn't exist within the database");
}
}


Currently nothing happens..the code just runs with the default form on the screen. Not loading the values, what am I doing wrong?

Answer

BGW is obsolete. The TPL, async/awaitand IProgress<T> can address all cases where BGW was used and more.

In this case, BGW isn't appropriate anyway. The real delay is caused by the database call, not loading the UI. To execute the database call asynchronously, you only have to use an asynchronous event handler:

private async void comboBox4_SelectedIndexChanged(object sender, EventArgs e)
{
        var conString=Properties.Settings.Default.MyConnectionString;
        string query = "SELECT * FROM dbo.Liguanea_Lane2";                    

        using(var con = new SqlConnection(conString))
        using(var cmd = new SqlCommand(query, con))
        {
            await con.OpenAsync();
            var reader=await cmd.ExecuteReader();
            while (dr.Read())
            {
                string scode = dr.GetString(dr.GetOrdinal("code"));
                comboBox2.Items.Add(scode);
            }
        }
}

There are better ways to load a combo though. One improvement is to load all items in a list, then use AddRange to update the combo. AddRange already calls BeginUpdate to prevent UI updates while adding items from the list.

        var items=new List<string>();
        using(var con = new SqlConnection(conString))
        using(var cmd = new SqlCommand(query, con))
        {
            await con.OpenAsync();
            var reader=await cmd.ExecuteReader();
            while (dr.Read())
            {
                string scode = dr.GetString(dr.GetOrdinal("code"));
                list.Add(scode);
            }
        }

        comboBox2.Items.AddRange(items);

Even better, use a micro-ORM like Dapper to get rid of all this code:

using(var con = new SqlConnection(conString))
{
    await con.OpenAsync();
    var items=await con.QueryAsync<string>(query);
    comboBox2.Items.AddRange(items);
}
Comments