用线程 c# 填充 datagridview
populate datagridview with thread c#
我正在尝试根据 sql 的查询填充数据网格视图,但这需要很长时间,我想做的是显示 .gif "loading" 同时填充网格,我正在使用线程,但 .gif 冻结,如果我使用 CheckForIllegalCrossThreadCalls = false;
,则 datagridview 不会加载滚动条,这很奇怪。这是我的代码
delegate void CambiarProgresoDelegado();
点击按钮
private void btn_busca_Click(object sender, EventArgs e)
{
pictureBox1.Visible = true;
thread= new Thread(new ThreadStart(ejecuta_sql));
thread.Start();
}
方法
private void ejecuta_sql()
{
if (this.InvokeRequired)
{
CambiarProgresoDelegado delegado = new CambiarProgresoDelegado(ejecuta_sql);
object[] parametros = new object[] { };
this.Invoke(delegado, parametros);
}
else
{
myConnection.Open();
SqlCommand sql_command2;
DataSet dt2 = new DataSet();
sql_command2 = new SqlCommand("zzhoy", myConnection);
sql_command2.CommandType = CommandType.StoredProcedure;
sql_command2.Parameters.AddWithValue("@FechaIni", dateTimePicker1.Value.ToShortDateString());
sql_command2.Parameters.AddWithValue("@FechaFin", dateTimePicker2.Value.ToShortDateString());
SqlDataAdapter da2 = new SqlDataAdapter(sql_command2);
da2.Fill(dt2, "tbl1");
grid_detalle.DataSource = dt2.Tables[0];
myConnection.Close();
pictureBox1.Visible = false;
}
并且 .gif 冻结,直到线程完成他的工作。
您创建了一个线程,但随后立即使用 Invoke() 将代码切换回主 UI 线程,从而抵消了创建线程的任何好处。
运行 在另一个线程上查询,然后 Invoke() 只是更新 UI:
的部分
private string FechaIni;
private string FechaFin;
private void btn_busca_Click(object sender, EventArgs e)
{
btn_busca.Enabled = false;
pictureBox1.Visible = true;
FechaIni = dateTimePicker1.Value.ToShortDateString();
FechaFin = dateTimePicker2.Value.ToShortDateString();
thread = new Thread(new ThreadStart(ejecuta_sql));
thread.Start();
}
private void ejecuta_sql()
{
myConnection.Open();
SqlCommand sql_command2;
DataSet dt2 = new DataSet();
sql_command2 = new SqlCommand("zzhoy", myConnection);
sql_command2.CommandType = CommandType.StoredProcedure;
sql_command2.Parameters.AddWithValue("@FechaIni", FechaIni);
sql_command2.Parameters.AddWithValue("@FechaFin", FechaFin);
SqlDataAdapter da2 = new SqlDataAdapter(sql_command2);
da2.Fill(dt2, "tbl1");
myConnection.Close();
this.Invoke((MethodInvoker)delegate {
grid_detalle.DataSource = dt2.Tables[0];
pictureBox1.Visible = false;
btn_busca.Enabled = true;
});
}
您可以考虑改变您的方法,尤其是当您从后台线程执行大量 GUI 更新时。原因:
- UI 更新需要时间,并且会减慢后台处理速度,因为您必须锁定
- 太多来自后台线程的更新会淹没 UI 并可能导致冻结。
- 您可能不想每毫秒左右更新一次 GUI
我更喜欢轮询后台线程数据。将 GUI 计时器设置为 300 毫秒,然后检查是否有任何数据准备好更新,然后通过适当的锁定进行快速更新。
这是代码示例:
private string text = "";
private object lockObject = new object();
private void MyThread()
{
while (true)
{
lock (lockObject)
{
// That can be any code that calculates text variable,
// I'm using DateTime for demonstration:
text = DateTime.Now.ToString();
}
}
}
private void timer_Tick(object sender, EventArgs e)
{
lock(lockObject)
{
label.Text = text;
}
}
请注意,虽然文本变量更新非常频繁,但 GUI 仍然保持响应。相反,如果您在每次 "text" 更改时更新 GUI,您的系统将冻结。
我正在尝试根据 sql 的查询填充数据网格视图,但这需要很长时间,我想做的是显示 .gif "loading" 同时填充网格,我正在使用线程,但 .gif 冻结,如果我使用 CheckForIllegalCrossThreadCalls = false;
,则 datagridview 不会加载滚动条,这很奇怪。这是我的代码
delegate void CambiarProgresoDelegado();
点击按钮
private void btn_busca_Click(object sender, EventArgs e)
{
pictureBox1.Visible = true;
thread= new Thread(new ThreadStart(ejecuta_sql));
thread.Start();
}
方法
private void ejecuta_sql()
{
if (this.InvokeRequired)
{
CambiarProgresoDelegado delegado = new CambiarProgresoDelegado(ejecuta_sql);
object[] parametros = new object[] { };
this.Invoke(delegado, parametros);
}
else
{
myConnection.Open();
SqlCommand sql_command2;
DataSet dt2 = new DataSet();
sql_command2 = new SqlCommand("zzhoy", myConnection);
sql_command2.CommandType = CommandType.StoredProcedure;
sql_command2.Parameters.AddWithValue("@FechaIni", dateTimePicker1.Value.ToShortDateString());
sql_command2.Parameters.AddWithValue("@FechaFin", dateTimePicker2.Value.ToShortDateString());
SqlDataAdapter da2 = new SqlDataAdapter(sql_command2);
da2.Fill(dt2, "tbl1");
grid_detalle.DataSource = dt2.Tables[0];
myConnection.Close();
pictureBox1.Visible = false;
}
并且 .gif 冻结,直到线程完成他的工作。
您创建了一个线程,但随后立即使用 Invoke() 将代码切换回主 UI 线程,从而抵消了创建线程的任何好处。
运行 在另一个线程上查询,然后 Invoke() 只是更新 UI:
的部分 private string FechaIni;
private string FechaFin;
private void btn_busca_Click(object sender, EventArgs e)
{
btn_busca.Enabled = false;
pictureBox1.Visible = true;
FechaIni = dateTimePicker1.Value.ToShortDateString();
FechaFin = dateTimePicker2.Value.ToShortDateString();
thread = new Thread(new ThreadStart(ejecuta_sql));
thread.Start();
}
private void ejecuta_sql()
{
myConnection.Open();
SqlCommand sql_command2;
DataSet dt2 = new DataSet();
sql_command2 = new SqlCommand("zzhoy", myConnection);
sql_command2.CommandType = CommandType.StoredProcedure;
sql_command2.Parameters.AddWithValue("@FechaIni", FechaIni);
sql_command2.Parameters.AddWithValue("@FechaFin", FechaFin);
SqlDataAdapter da2 = new SqlDataAdapter(sql_command2);
da2.Fill(dt2, "tbl1");
myConnection.Close();
this.Invoke((MethodInvoker)delegate {
grid_detalle.DataSource = dt2.Tables[0];
pictureBox1.Visible = false;
btn_busca.Enabled = true;
});
}
您可以考虑改变您的方法,尤其是当您从后台线程执行大量 GUI 更新时。原因:
- UI 更新需要时间,并且会减慢后台处理速度,因为您必须锁定
- 太多来自后台线程的更新会淹没 UI 并可能导致冻结。
- 您可能不想每毫秒左右更新一次 GUI
我更喜欢轮询后台线程数据。将 GUI 计时器设置为 300 毫秒,然后检查是否有任何数据准备好更新,然后通过适当的锁定进行快速更新。
这是代码示例:
private string text = "";
private object lockObject = new object();
private void MyThread()
{
while (true)
{
lock (lockObject)
{
// That can be any code that calculates text variable,
// I'm using DateTime for demonstration:
text = DateTime.Now.ToString();
}
}
}
private void timer_Tick(object sender, EventArgs e)
{
lock(lockObject)
{
label.Text = text;
}
}
请注意,虽然文本变量更新非常频繁,但 GUI 仍然保持响应。相反,如果您在每次 "text" 更改时更新 GUI,您的系统将冻结。