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.