c# – Working with backgroundworker c #

Question:

Good afternoon everyone! The program needed to implement sending a request to the database and receiving a response in a separate thread, I decided to turn to the backgroundworker. When you open the second form in the program and click on the checkbox, you need to start the third form (with a progress bar and a timer) and get the table from the base in the worker, after receiving it, display it in the datagrid on the second form and close the third. I wrote the following code, but it works strangely – the datagrid is not updated and the third form does not close automatically. What is the jamb? I also planned to add the ability to interrupt the work of the worker from the 3rd form by clicking on the "Interrupt" button, but so far I stopped at this, I managed to do it through Threads, but I want to implement it more correctly (the commented-out pieces of code remained from another idea)

public partial class Organizations : Form
{
    Progress ThirdForm;
    public Thread potok;
    public Thread potok1;
    public BackgroundWorker BW;

    public Organizations()
    {
        InitializeComponent();
        backgroundWorker1.DoWork +=
            new DoWorkEventHandler(backgroundWorker1_DoWork);
        backgroundWorker1.RunWorkerCompleted +=
            new RunWorkerCompletedEventHandler(
        backgroundWorker1_RunWorkerCompleted);
        backgroundWorker1.ProgressChanged +=
            new ProgressChangedEventHandler(
        backgroundWorker1_ProgressChanged);

        backgroundWorker1.WorkerSupportsCancellation = true;
    }

    public delegate void Del();

    DataTable Loading(BackgroundWorker worker, DoWorkEventArgs e)
    {
        bool b2 = false;
        DataTable dt;
        if (worker.CancellationPending)
        {
            e.Cancel = true;
        } 
        else
        { 
            // Получение строки соединения с базой данных и заполнение таблицы на CalculationForm
            var cn = new SqlConnection();
            SqlDataReader myReader = null;
            cn.ConnectionString = ConnString.GetConnectionString();
            cn.Open();
            //  Идентификатор расчета

            if (((Reports)(Application.OpenForms[0])).textBox1.Text == "")
            {
                MessageBox.Show("Необходимо сначала выбрать расчет!", "Обработчик кнопки Организации", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return dt = null;
            }
            else
            {
                int IdCostsResultTask = Convert.ToInt32(((Reports)(Application.OpenForms[0])).textBox1.Text);
                string sqlQuery = @" SELECT cr.ExportIdListEdu 'ExportIdListEdu', ReestrEdu.IdListEdu 'IdListEdu',slovar..ListEdu.Name 'ShortName', slovar..ListEdu.LongName 'Name' FROM ReestrEdu " +
                                   " LEFT JOIN slovar..ListEdu on ReestrEdu.IdListEdu = slovar..ListEdu.IdListEdu " +
                                   " LEFT JOIN CostsResult as cr on ReestrEdu.IdListEdu = cr.ExportIdListEdu or ReestrEdu.IdListEdu = cr.IdListEdu" +
                                   " WHERE cr.IdCostsResultTask = " + IdCostsResultTask + " and slovar..ListEdu.LongName is not null " +
                                   " Group By cr.ExportIdListEdu, ReestrEdu.IdListEdu, slovar..ListEdu.Name, slovar..ListEdu.LongName  ORDER BY 1,2 ";
                var myCommand = new SqlCommand(sqlQuery, cn);
                myCommand.CommandTimeout = 600;
                myReader = myCommand.ExecuteReader();
                using (myReader)
                {
                    var table = new System.Data.DataTable();
                    table.Load(myReader);
                    dt = table;
                }
                myReader.Dispose();
                cn.Close();

                b2 = true;
            }
        }
        return dt;   
    }

    DataTable Loading2(BackgroundWorker worker, DoWorkEventArgs e)
    {
        bool b2 = false;
        DataTable dt2;
        if (worker.CancellationPending)
        {
            e.Cancel = true;
        } 
        else
        { 
            // Получение строки соединения с базой данных и заполнение таблицы на CalculationForm
            var cn = new SqlConnection();
            SqlDataReader myReader = null;
            cn.ConnectionString = ConnString.GetConnectionString();
            cn.Open();
            //  Идентификатор расчета
            if (((Reports)(Application.OpenForms[0])).textBox1.Text == "")
            {
                MessageBox.Show("Необходимо сначала выбрать расчет!", "Обработчик кнопки Организации", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return dt2 = null;
            }
            else
            {
                int IdCostsResultTask = Convert.ToInt32(((Reports)(Application.OpenForms[0])).textBox1.Text);
                string sqlQuery = @" SELECT cr.ExportIdListEdu 'ExportIdListEdu', ReestrEdu.IdListEdu 'IdListEdu',slovar..ListEdu.Name 'ShortName', slovar..ListEdu.LongName 'Name' FROM ReestrEdu " +
                                   " LEFT JOIN slovar..ListEdu on ReestrEdu.IdListEdu = slovar..ListEdu.IdListEdu " +
                                   " LEFT JOIN CostsResult as cr on ReestrEdu.IdListEdu = cr.ExportIdListEdu" +
                                   " WHERE cr.IdCostsResultTask = " + IdCostsResultTask + " and slovar..ListEdu.LongName is not null " +
                                   " Group By cr.ExportIdListEdu, ReestrEdu.IdListEdu, slovar..ListEdu.Name, slovar..ListEdu.LongName  ORDER BY 1 ";
                var myCommand = new SqlCommand(sqlQuery, cn);
                myCommand.CommandTimeout = 600;
                myReader = myCommand.ExecuteReader();
                using (myReader)
                {
                    var table = new System.Data.DataTable();
                    table.Load(myReader);
                dt2 = table;
                }
                myReader.Dispose();
                cn.Close();

                b2 = true;
            }  
        }
        return dt2;
    }

    private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy != true)
        {
            // Start the asynchronous operation.
            backgroundWorker1.RunWorkerAsync();
        }
    }

    private void OrgDatagrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        ((Reports)(Application.OpenForms[0])).listBox1.Items.Insert(0, "1");  
        this.Close();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        if (checkBox1.Checked)
        {
            ThirdForm = new Progress();
            ThirdForm.ShowDialog();
            e.Result = Loading(worker, e);
        }
        else
        {
            ThirdForm = new Progress();
            ThirdForm.ShowDialog();
            e.Result = Loading2(worker, e);
        }
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            MessageBox.Show(e.Error.Message);
        }            
        else
        {
            ThirdForm.Close();
            OrgDatagrid.DataSource = e.Result;
        }
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
    }
}

Form 3 code (with timer, progress bar and asynchronous operation cancellation button):

 public partial class Progress : Form
{


    public Progress()
    {
        InitializeComponent();
        // Обрабатываем событие таймера.
        timer1.Interval = 1000;
        timer1.Start();

    }

    public void timer1_Tick(object sender, EventArgs e)
    {
        TimeLabel.Text = DateTimer.ToString("mm:ss");
        DateTimer = DateTimer.AddSeconds(1);
    }

    private void BtnCancel_Click(object sender, EventArgs e)
    {
        Organizations f = new Organizations();            
        if (f.backgroundWorker1.WorkerSupportsCancellation == true)
        {
            // Cancel the asynchronous operation.
            f.backgroundWorker1.CancelAsync();
        }
    }

UPD: Solved the problem by moving the ThirdForm call to the checkBox1_CheckedChanged method after calling the worker. The trouble was precisely in calling 3 forms from backgroundWorker1_DoWork. Inside worker methods, these calls do not work correctly (at least not the way we would like). However, another problem remains – the button for canceling the operation in the worker from the 3rd form does not work (just nothing happens). I do not yet understand how to correctly call the worker termination from another form.

UPD2: The problem with the button is solved as follows:

Changes in the code on form 3:

public event EventHandler Cancel = delegate { };

private void BtnCancel_Click(object sender, EventArgs e)
    {
        Cancel(sender, e);
        timer1.Stop();           
    }

Processing in the second form:

void CancelProcess(object sender, EventArgs e)
    {
        backgroundWorker1.CancelAsync();
        if (checkflag)
        {
            checkBox1.Checked = false;
            ThirdForm.Close();
            ThirdForm.timer1.Stop();
            ThirdForm.TimeLabel.Text = "";
            ThirdForm.DateTimer = new DateTime(0, 0);
        }
        else
        {
        checkBox1.Checked = true;
        //backgroundWorker1.Dispose();            
        ThirdForm.Close();
        ThirdForm.timer1.Stop();
        ThirdForm.TimeLabel.Text = "";
        ThirdForm.DateTimer = new DateTime(0, 0);
        }
    }

private void checkBox1_CheckedChanged(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy != true)
        {
            // Start the asynchronous operation.
            checkflag = checkBox1.Checked;
            ThirdForm = new Progress();
            ThirdForm.timer1.Stop();
            ThirdForm.TimeLabel.Text = "";
            ThirdForm.Cancel += CancelProcess;
            backgroundWorker1.RunWorkerAsync();
            ThirdForm.timer1.Start();
            ThirdForm.ShowDialog();
        }
    }

Answer:

The form should close or display an error message (either a MessageBox, or the program will crash). The error may not appear if it did not occur on the main thread (for example, if backgroundWorker1_RunWorkerCompleted was triggered on a different thread).

I suggest just in case to insert Invoke inside this method

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    this.Invoke(new Action(() =>
       if (e.Error != null)
       {
           MessageBox.Show(e.Error.Message);
       }            
       else
       {
           ThirdForm.Close();
           OrgDatagrid.DataSource = e.Result;
           MessageBox.Show("Работа завершена");
       }
   ));
}

At the same time, I added an extra MessageBox to make sure that backgroundWorker1_RunWorkerCompleted works at all.

As for interrupting the BackgroundWorker using the Abort () method, as for Thread, unfortunately it does not support it. Of course, it is undesirable to do Abort (), since remains dead Connection. Although the garbage collector will close it later.

I think it makes sense to completely abandon the BackgroundWorker and implement everything on the Thread, placing all the code for working with the interface in Invoke () (forms cannot be changed in another thread).

Scroll to Top
AllEscort