Search code examples
c#sql-serverc#-4.0datagridviewdatagridviewcombobox

Progress bar taking 20 seconds to start when it should start right away after selecting a value of a combobox in C# WindowsForms


I am having an issue with my program. my program will let the user select a dropdown value and after they select the dropdown value the datagridview should load with the data from a table, and then the progress bar should start the percentage 1 to 100%. Now everything in my program works the datagridview loads correctly and everything else in the program. the progress bar also works and loads but the issue comes when the user selects the dropdow combobox the progress bar takes like 15 to 20 seconds to start. I would like it to right away.

Can you see my code and see what could be the issue to why the progress bar is not starting right away?

if you need more information please let me know.

namespace DatagridViewProgressBar
{
    public partial class Form1 : Form
    {

        //datagridview, bindingsource, data_apapter global objects variables
        private DataGridView dataGridView = new DataGridView();
        private BindingSource bindingSource = new BindingSource();
        private SqlDataAdapter dataAdapter = new SqlDataAdapter();
        DataTable dt = new DataTable();


        //class objects
        Databases lemars = new Databases();
        Databases schuyler = new Databases();
        Databases detroitlakeskc = new Databases();


        public Form1()
        {
            InitializeComponent();
            // To report progress from the background worker we set this property
            dbWorker = new BackgroundWorker();
            dbWorker.DoWork += new DoWorkEventHandler(dbWorker_DoWork);
            dbWorker.ProgressChanged += new ProgressChangedEventHandler(dbWorker_ProgressChanged);
            dbWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(dbWorker_RunWorkerCompleted);
            dbWorker.WorkerReportsProgress = true;
            dbWorker.WorkerSupportsCancellation = true;

        }

        private void btn_Exit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void comboBox_Database_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox_Database.SelectedItem.ToString() == "LeMars21St")
            {

                if (dbWorker.IsBusy != true)
                {
                    dbWorker.RunWorkerAsync();
                }            
            }
        }



        private void GetTableToDataGridView()
        {
            //prgBar_DataGridViewLoading
            DatabaseColumns Obj = new DatabaseColumns();
            String SqlcmdString = @"SELECT invoice, shipment, Project, invoiceDateTB, CreatedDate, typeName, exportedDate, statusName, total, import_status, Time_Completed, ERROR_DESCRIPTION FROM dbo.AllInvoicesInReadyStatus";
            SqlDataReader reader;
            int progress;

            using (SqlConnection conn = new SqlConnection(lemars._LeMarsConnectionString))
            {
                reader = null;
                SqlCommand Sqlcmd = new SqlCommand(SqlcmdString, conn);
                conn.Open();
                reader = Sqlcmd.ExecuteReader();
                if (reader.HasRows)
                {
                    try
                    {

                        dt.Load(reader);

                        for (int i = 0; i < dt.Rows.Count; i++)
                        {
                            Obj.Invoice = dt.Rows[i]["invoice"].ToString();
                            Obj.Shipment = dt.Rows[i]["shipment"].ToString();
                            Obj.Project = dt.Rows[i]["Project"].ToString();
                            Obj.InvoiceDateTB = Convert.ToDateTime(dt.Rows[i]["invoiceDateTB"]);
                            Obj.CreatedDate = Convert.ToDateTime(dt.Rows[i]["CreatedDate"]);
                            Obj.TypeName = dt.Rows[i]["typeName"].ToString();
                            Obj.ExportedDate = Convert.ToDateTime(dt.Rows[i]["exportedDate"]);
                            Obj.StatusName = dt.Rows[i]["statusName"].ToString();
                            Obj.Total = Convert.ToDecimal(dt.Rows[i]["total"]);
                            Obj.ImportStatus = dt.Rows[i]["import_status"].ToString();
                            if (!Convert.IsDBNull(dt.Rows[i]["Time_Completed"]))
                            {
                                Obj.TimeCompleted = Convert.ToDateTime(dt.Rows[i]["Time_Completed"]);
                            }
                            Obj.ErrorDescription = dt.Rows[i]["ERROR_DESCRIPTION"].ToString();

                            progress = i * 100 / dt.Rows.Count; 
                            dbWorker.ReportProgress(progress);
                            Thread.Sleep(500);
                        }                     
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        private void dbWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            GetTableToDataGridView();
            dbWorker.ReportProgress(100);
        }

        private void dbWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar_GetTasks.Value = e.ProgressPercentage;
            // eg: Set your label text to the current value of the progress bar
            lbl_PercentageCount.Text = (progressBar_GetTasks.Value.ToString() + "%");         
        }

        private void dbWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

            dataGridView_ShowAllData.DataSource = dt;

            if (e.Cancelled)
            {
                 MessageBox.Show("Process Cancelled.");
            }
            else if (e.Error != null)
            {
                MessageBox.Show("Error occurred: " + e.Error.Message);
            }
            else
            {
                MessageBox.Show("Successful Completion.");
            }

            //progressBar_GetTasks.Value = 0;
        }

        private void btn_CancelOperation_Click(object sender, EventArgs e)
        {
            if (dbWorker.IsBusy)
            {
                dbWorker.CancelAsync();
            }
        }
    }
}

Solution

  • Doing dt.Load(reader); waits for the data to fully load before continuing, Get rid of that line and replace it with a while(reader.Read()) loop.

        private void GetTableToDataGridView()
        {
            //prgBar_DataGridViewLoading
            DatabaseColumns Obj = new DatabaseColumns();
            String SqlcmdString = @"SELECT invoice, shipment, Project, invoiceDateTB, CreatedDate, typeName, exportedDate, statusName, total, import_status, Time_Completed, ERROR_DESCRIPTION FROM dbo.AllInvoicesInReadyStatus";
            String CountcmdString = @"SELECT count(*) FROM dbo.AllInvoicesInReadyStatus";
            SqlDataReader reader;
            int progress;
            int total;
    
            using (SqlConnection conn = new SqlConnection(lemars._LeMarsConnectionString))
            {
                reader = null;
                SqlCommand Sqlcmd = new SqlCommand(CountcmdString , conn);
                conn.Open();
                total = (int)Sqlcmd.ExecuteScalar(); //Get the total count.
                Sqlcmd.CommandText = SqlcmdString;
                using(reader = Sqlcmd.ExecuteReader()) //this should be in a using statement
                {
                    while(reader.Read())
                    {
                        object[] row = new object[reader.VisibleFieldCount];
                        reader.GetValues(row);
                        LoadSingleRowInToTable(dt, row); //I leave this to you to write.
    
                        //You can just read directly from the reader.
                        Obj.Invoice = reader["invoice"].ToString();
                        Obj.Shipment = reader["shipment"].ToString();
                        Obj.Project = reader["Project"].ToString();
                        Obj.InvoiceDateTB = Convert.ToDateTime(reader["invoiceDateTB"]);
                        Obj.CreatedDate = Convert.ToDateTime(reader["CreatedDate"]);
                        Obj.TypeName = reader["typeName"].ToString();
                        Obj.ExportedDate = Convert.ToDateTime(reader["exportedDate"]);
                        Obj.StatusName = reader["statusName"].ToString();
                        Obj.Total = Convert.ToDecimal(reader["total"]);
                        Obj.ImportStatus = reader["import_status"].ToString();
                        if (!Convert.IsDBNull(reader["Time_Completed"]))
                        {
                            Obj.TimeCompleted = Convert.ToDateTime(reader["Time_Completed"]);
                        }
                        Obj.ErrorDescription = reader["ERROR_DESCRIPTION"].ToString();
    
                        //Only call report progress when the progress value changes.
                        var newProgress = i * 100 / total;
                        if(progress != newProgress)
                        {
                            progress = newProgress;
                            dbWorker.ReportProgress(progress);
                        }
                        //Thread.Sleep(500); 
                    }
                }
            }
        }
    

    UPDATE: Here is a example based on Steve's deleted answer that shows a better solution without using a DataTable.

    private void dbWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        List<DatabaseColumns> data = GetTableToList();
        if (data == null) //data will be null if we canceled.
        {
            e.Cancel = true;
        }
        else
        {
            e.Result = data;
        }
        dbWorker.ReportProgress(100);
    }
    private void dbWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
    
        if (e.Cancelled)
        {
            MessageBox.Show("Process Cancelled.");
        }
        else if (e.Error != null)
        {
            MessageBox.Show("Error occurred: " + e.Error.Message);
        }
        else
        {
            dataGridView_ShowAllData.DataSource = e.Result; //use the result from thebackground worker, only use if not canceled or errored.
            MessageBox.Show("Successful Completion.");
        }
    
        //progressBar_GetTasks.Value = 0;
    }
    private List<DatabaseColumns> GetTableToList()
    {
        List<DatabaseColumns> data = new List<DatabaseColumns>();
        //prgBar_DataGridViewLoading
        String SqlcmdString = @"SELECT invoice, shipment, Project, invoiceDateTB, CreatedDate, typeName, exportedDate, statusName, total, import_status, Time_Completed, ERROR_DESCRIPTION FROM dbo.AllInvoicesInReadyStatus";
        String CountcmdString = @"SELECT count(*) FROM dbo.AllInvoicesInReadyStatus";
    
        using (SqlConnection conn = new SqlConnection(lemars._LeMarsConnectionString))
        {
            SqlCommand Sqlcmd = new SqlCommand(CountcmdString, conn);
            conn.Open();
            var total = (int)Sqlcmd.ExecuteScalar();
            Sqlcmd.CommandText = SqlcmdString;
            int i = 0;
            int progress = 0;
            using (SqlDataReader reader = Sqlcmd.ExecuteReader()) //this should be in a using statement
            {
                while (reader.Read())
                {
                    if (dbWorker.CancellationPending)
                    {
                        //Exit early if operation was canceled.
                        return null;
                    }
                    DatabaseColumns Obj = new DatabaseColumns();
    
                    //You can just read directly from the reader.
                    Obj.Invoice = reader["invoice"].ToString();
                    Obj.Shipment = reader["shipment"].ToString();
                    Obj.Project = reader["Project"].ToString();
                    Obj.InvoiceDateTB = Convert.ToDateTime(reader["invoiceDateTB"]);
                    Obj.CreatedDate = Convert.ToDateTime(reader["CreatedDate"]);
                    Obj.TypeName = reader["typeName"].ToString();
                    Obj.ExportedDate = Convert.ToDateTime(reader["exportedDate"]);
                    Obj.StatusName = reader["statusName"].ToString();
                    Obj.Total = Convert.ToDecimal(reader["total"]);
                    Obj.ImportStatus = reader["import_status"].ToString();
                    if (!Convert.IsDBNull(reader["Time_Completed"]))
                    {
                        Obj.TimeCompleted = Convert.ToDateTime(reader["Time_Completed"]);
                    }
                    Obj.ErrorDescription = reader["ERROR_DESCRIPTION"].ToString();
    
                    //Add the object to the list.
                    data.Add(Obj);
    
                    //Only call report progress when the progress value changes.
                    var newProgress = i * 100 / total;
                    if (progress != newProgress)
                    {
                        progress = newProgress;
                        dbWorker.ReportProgress(progress);
                    }
                    i++;
                }
            }
        }
        return data;
    }