简体   繁体   中英

populate datagridview with thread c#

Im trying to populate a datagridview from a query of sql but it takes a long time , what im trying to do is show a .gif "loading" meanwhile is populating the grid, im using threads but the .gif freezes , and if I use the CheckForIllegalCrossThreadCalls = false; the datagridview doesnt load the scroll bar acts weird. here is my code

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();
    }

method

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;


        }

and the .gif freezes until the thread finish his job.

You created a thread but then immediately made the code switch back to the main UI thread with Invoke(), negating any benefits of making the thread in the first place.

Run the query on the other thread, then Invoke() just the part that updates the 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;
        });
    }

You may consider changing your approach, especially if you are doing a lot of GUI updates from your background threads. Reasons:

  • UI update takes time and it slows down background processing as you have to lock
  • too many updates coming from the background threads will overwhelm the UI and might cause freezes.
  • you probably don't want to update GUI every millisecond or so

What I prefer is to do polling the background thread data instead. Set up GUI timer for say 300ms, then check if there is any data ready to be updated, then do quick update with proper locking.

Here is code example:

    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;
        }
    }

Note, that while the text variable is updated very frequently the GUI still stays responsive. If, instead, you update GUI on each "text" change, your system will freeze.

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