用线程c#填充datagridview

时间:2015-01-07 14:12:05

标签: c# multithreading datagridview

我试图从sql的查询中填充datagridview但是需要很长时间,我试图做的是显示.gif“loading”同时填充网格,我使用线程,但.gif冻结,和如果我使用CheckForIllegalCrossThreadCalls = false; datagridview没有加载滚动条的行为很奇怪。这是我的代码

delegate void CambiarProgresoDelegado(); 

BUTTON CLICK

 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冻结,直到线程完成他的工作。

2 个答案:

答案 0 :(得分:3)

您创建了一个线程,但随后立即使用Invoke()将代码切换回主UI线程,否定了首先创建线程的任何好处。

在另一个线程上运行查询,然后只调用()更新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;
        });
    }

答案 1 :(得分:2)

您可以考虑更改方法,尤其是在您从后台线程执行大量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仍然保持响应。相反,如果您在每个"文本"上更新GUI。改变,你的系统将冻结。