简体   繁体   中英

Get information from UI with BackgroundWorker and then update UI

I am filling a DataGridView by running a SQL query with BackgroundWorker . My code works perfectly if I run it directly in a button event handler, but when I put in a DoWork BackgroundWorker it doesn't update the UI. My code is below.

DataTable tab1table = new DataTable();

public Form1()
{
    InitializeComponent();
    Instantiatesearch1Thread();
}

private void Instantiatesearch1Thread()
{
    search1Thread.WorkerReportsProgress = true;
    search1Thread.WorkerSupportsCancellation = true;
    search1Thread.ProgressChanged += search1Thread_ProgressChanged;
    search1Thread.DoWork += search1Thread_Dowrk;
    search1Thread.RunWorkerCompleted += search1Thread_RunWorkerCompleted;
}

    private void sbutton1_Click(object sender, EventArgs e)
{
    search1Thread.RunWorkerAsync();
}
void search1Thread_Dowrk(object sender, DoWorkEventArgs e)
{
    int percentprogress = 0;
    percentprogress++;
    Thread.Sleep(1000);
    // Search1 button event handler
    using (SqlConnection conn = new SqlConnection(connectionstring))
    {

        conn.Open();
        using (SqlDataAdapter cmd = new SqlDataAdapter(comboBox1SQL, conn))
        {
            if (comboBox1.Text.Contains("ID"))
            {
                long para = long.Parse(search1.Text);
                cmd.SelectCommand.Parameters.Add(new SqlParameter
                {
                    ParameterName = "@combo1Par",
                    Value = para,
                    SqlDbType = SqlDbType.BigInt
                });
            }

            else if (comboBox1.Text.Contains("Other Thing") || comboBox1.Text.Contains("Other Stuff"))
            {
                string para = search1.Text;
                cmd.SelectCommand.Parameters.Add(new SqlParameter
                {
                    ParameterName = "@combo1Par",
                    Value = "%" + para + "%",
                    SqlDbType = SqlDbType.NVarChar,
                });
            }
            // Clear datatable if it contains any information and then fill it
            // tab1datatable is a DataGridView
            if (tab1table != null)
                tab1table.Clear();
            cmd.Fill(tab1table);
            //tab1datatable.DataSource = tab1table;

        // A bunch of expensive calculations 
        }
    }
}

void search1Thread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    search1Progress.Value = e.ProgressPercentage;
}

void search1Thread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    tab1datatable.DataSource = tab1table;
    tab1datatable.Refresh();
    MessageBox.Show("All Done!");
}

By using a MessageBox I discovered that the code is not accessing the if comboBox1.Text.Contains() statements, which I think makes sense, because that information comes from the UI and BackgroundWorker can't directly access the UI. This would also explain why then tab1datatable and tab1table go untouched.

I think I need to use the Invoke method somewhere, but I am not sure how. I took a look at c# - Pass information to BackgroundWorker From UI during execution but it doesn't really answer my question. If Invoke is what I need, how do I implement in this code to allow it to grab information from the UI and subsequently update it with the filled DataGridView ?

Here's what you need to do:

    private string search1_Text = "";
    private string comboBox1_Text = "";
    private void Instantiatesearch1Thread()
    {
        search1_Text = search1.Text;
        comboBox1_Text = comboBox1.Text;
        search1Thread.WorkerReportsProgress = true;
        search1Thread.WorkerSupportsCancellation = true;
        search1Thread.ProgressChanged += search1Thread_ProgressChanged;
        search1Thread.DoWork += search1Thread_Dowrk;
        search1Thread.RunWorkerCompleted += search1Thread_RunWorkerCompleted;
    }

You basically take a copy of the data that you need before you run the background worker.

Then you just access the fields in your DoWork code:

    void search1Thread_Dowrk(object sender, DoWorkEventArgs e)
    {
        int percentprogress = 0;
        percentprogress++;
        Thread.Sleep(1000);
        // Search1 button event handler
        using (SqlConnection conn = new SqlConnection(connectionstring))
        {
            conn.Open();
            using (SqlDataAdapter cmd = new SqlDataAdapter(comboBox1SQL, conn))
            {
                if (comboBox1_Text.Contains("ID"))
                {
                    long para = long.Parse(search1_Text);
                    cmd.SelectCommand.Parameters.Add(new SqlParameter
                    {
                        ParameterName = "@combo1Par",
                        Value = para,
                        SqlDbType = SqlDbType.BigInt
                    });
                }

                else if (comboBox1_Text.Contains("Other Thing") || comboBox1_Text.Contains("Other Stuff"))
                {
                    string para = search1_Text;
                    cmd.SelectCommand.Parameters.Add(new SqlParameter
                    {
                        ParameterName = "@combo1Par",
                        Value = "%" + para + "%",
                        SqlDbType = SqlDbType.NVarChar,
                    });
                }
                // Clear datatable if it contains any information and then fill it
                // tab1datatable is a DataGridView
                if (tab1table != null)
                    tab1table.Clear();
                cmd.Fill(tab1table);
                //tab1datatable.DataSource = tab1table;

                // A bunch of expensive calculations 
            }
        }
    }

I am not sure if this is a good solution or not but this works. Set CheckForIllegalCrossThreadCalls to false when you initialize the BackgroundWorker .

private void Instantiatesearch1Thread()
{
    // Initialize other stuff
    CheckForIllegalCrossThreadCalls = false;
}

And set it to false once task is completed.

private void search1Thread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Do your work,
    CheckForIllegalCrossThreadCalls = true;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM