【问题标题】:How to add a progress bar to a DataGridView while loading the data 1 to 100% when complete loading如何在加载数据时向 DataGridView 添加进度条 完成加载时 1 到 100%
【发布时间】:2017-08-01 16:11:30
【问题描述】:

我需要有关我的应用程序的帮助,我的应用程序中的一切都正常,但我想添加最后一个细节,以帮助用户使用该应用程序。

我有一个组合框,其中包含三个用户将使用的选项,每个选项都有不同的仓库数据库环境。因此,如果他们在组合框warehouse1 中选择,那么会将数据库 1 表数据加载到 datagridview,但是当他们选择应用程序时正在加载以显示数据,因此何时执行此操作取决于数据量有时需要 5 到 15 秒才能加载或更多我想添加一个进度条,以便让用户知道等到进度达到 100%。

因此,我需要有关如何在 datagridview 加载数据时使进度条正常工作的帮助。如果您需要更多信息,请告诉我。

更改后请检查,但我收到错误消息 [![在此处输入图片描述][1]][1]

        //the issue I am having is the progress bar to while the datagridview is loading, the datagridview will load after the user selects the combobox selection
        //the combobox event handler will fill the datagridview and the forms loads and I want while loading the progress bar to show the percentage that is loading 1 to 100%

更新代码: //全局变量 //datagridview, bindingsource, data_aapter 全局对象变量 私有 DataGridView dataGridView = new DataGridView(); 私有 BindingSource bindingSource = new BindingSource(); 私有 SqlDataAdapter dataAdapter = new SqlDataAdapter();

    //class objects
    Databases lemars = new Databases();
    Databases schuyler = new Databases();
    Databases detroitlakeskc = new Databases();
    /*
     *   The GetLeMarsConnectionDatabaseConnection method starts the database string connection for warehouse LeMars21St 
    */
    private void GetLeMarsConnectionDatabaseConnection(string selectCommand, Databases database)
    {

        try
        {

            //Create the connection string, data adapter and data table.
            String connectionString = database.LeMarsConnectionString;


            // Specify a connection string. Replace the given value with a 
            // valid connection string for a Northwind SQL Server sample
            // database accessible to your system.
            // Create a new data adapter based on the specified query.
            dataAdapter = new SqlDataAdapter(selectCommand, connectionString);

            // Create a command builder to generate SQL update, insert, and
            // delete commands based on selectCommand. These are used to
            // update the database.
            SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter);

            // Populate a new data table and bind it to the BindingSource.
            System.Data.DataTable table = new System.Data.DataTable();
            table.Locale = System.Globalization.CultureInfo.InvariantCulture;
            dataAdapter.Fill(table);
            bindingSource.DataSource = table;

            // Resize the DataGridView columns to fit the newly loaded content.
            dataGridView_ShowAllData.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);

        }
        //catch the error if cannot get a database connection
        catch (SqlException)
        {
            MessageBox.Show("FootPrint-LEMARS Database couldn't received a connection ***ERROR***");
        }

    }


    private void cmb_DatabaseSelection_SelectedIndexChanged(object sender, EventArgs e)
    {

        //Boolean selection statements to Fill the DataGridView based on the user selecction
        if (cmb_DatabaseSelection.SelectedItem == "LeMars21St")
        {
            dataGridView_ShowAllData.DataSource = bindingSource;

            //query with 11 columns
            GetLeMarsConnectionDatabaseConnection("Select * from dbo.AllInvoicesInReadyStatus", lemars);


        }

        private void bgnWorker_LoadingForm_DoWork(object sender, DoWorkEventArgs e)
    {
        // TODO: query your database
        // for easier reading I assume that your query-result has only one column
        //string query = @"Select * from dbo.AllInvoicesInReadyStatus";
        //** did you strip your sql-execution-code? have a look at https://msdn.microsoft.com/de-de/library/system.data.sqlclient.sqlcommand.aspx


        var queryResult = new List<object>();
        bgnWorker_LoadingForm.ReportProgress(10);

        var table = new System.Data.DataTable();
        // TODO: create matching columns for your query-result in the datatable
        // https://msdn.microsoft.com/de-de/library/system.data.datatable.newrow(v=vs.110).aspx
        // Create new DataTable and DataSource objects. 

        // Declare DataColumn and DataRow variables.
        DataColumn column;
        DataRow row;
        DataView view;

        // Create new DataColumn, set DataType, ColumnName, and add to DataTable.    
        column = new DataColumn();
        column.DataType = typeof(string);
        column.ColumnName = "invoice";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = typeof(string);
        column.ColumnName = "shipment";
        table.Columns.Add(column);

        // Create third column. 
        column = new DataColumn();
        column.DataType = typeof(string);
        column.ColumnName = "Project";
        table.Columns.Add(column);

        // Create fourth column. 
        column = new DataColumn();
        column.DataType = typeof(DateTime);
        column.ColumnName = "invoiceDateTB";
        table.Columns.Add(column);

        // Create fifth column. 
        column = new DataColumn();
        column.DataType = typeof(DateTime);
        column.ColumnName = "CreatedDate";
        table.Columns.Add(column);

        // Create sixth column. 
        column = new DataColumn();
        column.DataType = typeof(string);
        column.ColumnName = "typeName";
        table.Columns.Add(column);

        // Create seventh column. 
        column = new DataColumn();
        column.DataType = typeof(string);
        column.ColumnName = "statusName";
        table.Columns.Add(column);

        // Create eighth column. 
        column = new DataColumn();
        column.DataType = typeof(decimal);
        column.ColumnName = "total";
        table.Columns.Add(column);

        // Create ninth column. 
        column = new DataColumn();
        column.DataType = typeof(string);
        column.ColumnName = "import_status";
        table.Columns.Add(column);

        // Create tenth column. 
        column = new DataColumn();
        column.DataType = typeof(DateTime); 
        column.ColumnName = "Time_Completed";
        table.Columns.Add(column);

        // Create eleventh column. 
        column = new DataColumn();
        column.DataType = typeof(string);
        column.ColumnName = "ERROR_DESCRIPTION";
        table.Columns.Add(column);



        for (var i = 0; i < queryResult.Count; i++)
        {
            var progress = 10 + (int)((float)i / queryResult.Count) * 90;
            bgnWorker_LoadingForm.ReportProgress(progress);
            //** dont know whats going on here
            //** but normally you should iterate your data-reader here and transfer the data of your query result to the created row... like this: https://msdn.microsoft.com/de-de/library/haa3afyz(v=vs.110).aspx
            row = table.NewRow();
            row["invoice"].ToString();
            row["shipment"].ToString();
            row["Project"].ToString();
            row["invoiceDateTB"] = typeof(DateTime);
            row["CreatedDate"] = typeof(DateTime);
            row["typeName"].ToString();
            row["statusName"].ToString();
            row["total"] = typeof(decimal);
            row["import_status"].ToString();
            row["Time_Completed"] = typeof(DateTime);
            row["ERROR_DESCRIPTION"].ToString();

            table.Rows.Add(row);

            // TODO: add the row data to the table
            // same link as before: https://msdn.microsoft.com/de-de/library/system.data.datatable.newrow(v=vs.110).aspx
        }

        //**begin: move this stuff to worker completed
        // Create a DataView using the DataTable. . 
        view = new DataView(table);
        //**end

        // Set a DataGrid control's DataSource to the DataView.
        dataGridView_ShowAllData.DataSource = view;

        e.Result = table;
    }

    private void bgnWorker_LoadingForm_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        System.Data.DataTable table = (System.Data.DataTable)e.Result;
        // TODO: Check for errors
        // TODO: Assign the table to your grid
        // TODO: unlock your ui, hide progress dialog
    }

    private void bgnWorker_LoadingForm_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // TODO: update your progress dialog/progressbar, f.e.
        prgBar_DataGridViewLoading.Value = e.ProgressPercentage;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (bgnWorker_LoadingForm.IsBusy) return;
        bgnWorker_LoadingForm.RunWorkerAsync();
        // TODO: lock your ui, show progress dialog or progressbar...
    }

【问题讨论】:

  • 您无法使用填充方法来执行此操作,因为您无法控制循环。您必须调整查询和代码以获取记录计数,然后循环通过记录以使用单独的线程填充您的表。或者只是将进度条设置为标记样式。
  • 我明白了,你能举例说明在填充 datadridview 或进度条标记样式时进行控制
  • progressBar1.Style = ProgressBarStyle.Marquee;
  • 你能展示一个完整的代码它是如何工作的吗?我对进度条或datagridview的控制做得不多
  • 你的代码根本无法做到这一点。您必须编写不同的 sql 来获取数据块,并在执行每个查询后增加进度条。这会增加大量复杂性并使整个过程变慢。

标签: c# sql-server c#-4.0


【解决方案1】:

如果您想要“真正的”进度,则必须使用 BackgroundWorker (WorkerReportsProgress = true) 手动操作...

简明扼要的描述:

1) 在BackgroundWorker.DoWork 函数中查询您的表(例如 10%),在本地创建匹配的 DataTable,迭代结果并将其添加到您的本地 DataTable(10-100%)。

2) 使用ReportProgress 将当前进度状态从BackgroundWorker.DoWork 内部发送到您的用户界面。

3) 在BackgroundWorker.ProgressChanged,您可以安全地更新您的 ui/progressbar。

4) 然后返回(赋值给DoWorkEventArgs.Result)本地DataTable作为BackgroundWorker.DoWork的结果...

5) 并通过访问RunWorkerCompletedEventArgs.Result 检索BackgroundWorker.RunWorkerCompleted 中的结果并将DataTable 分配给您的DataGrid

简单粗暴的例子...

public partial class Form1 : Form
{
    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        // TODO: query your database
        // for easier reading I assume that your query-result has only one column
        var queryResult = new List<object>();
        backgroundWorker1.ReportProgress(10);

        var table = new DataTable();
        // TODO: create matching columns for your query-result in the datatable
        // https://msdn.microsoft.com/de-de/library/system.data.datatable.newrow(v=vs.110).aspx

        for (var i = 0; i < queryResult.Count; i++)
        {
            var progress = 10 + (int)((float)i / queryResult.Count) * 90;
            backgroundWorker1.ReportProgress(progress);

            // TODO: add the row data to the table
            // same link as before: https://msdn.microsoft.com/de-de/library/system.data.datatable.newrow(v=vs.110).aspx
        }

        e.Result = table;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        DataTable table = (DataTable)e.Result;
        // TODO: Check for errors
        // TODO: Assign the table to your grid
        // TODO: unlock your ui, hide progress dialog
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // TODO: update your progress dialog/progressbar, f.e.
        progressBar1.Value = e.ProgressPercentage;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy) return;
        backgroundWorker1.RunWorkerAsync();
        // TODO: lock your ui, show progress dialog or progressbar...
    }
}

未测试,因为我有 a) 没有测试数据和 b) 构建一个完整的示例非常耗时。我也可能忘记了一些事情,但这可能是一种方法......

【讨论】:

  • 我会检查这个,如果我有其他问题,我会告诉你,但如果不问太多,你可以提供你的陈述的示例代码
  • 对不起,我没有看到你的代码示例,我会做一个测试,让你知道结果
  • Select * from dbo.AllInvoicesInReadyStatus 查询将显示 11 列数据
  • 我做了更改,请检查我的问题,如果我遗漏了什么,请检查上面
  • @AndresBryan29 首先:您的代码在这里变得非常大 - 尽量保持小!关于代码... 1) DoWork 函数中仍然缺少 sql-query-execution。您仍在DoWork 函数中分配创建的DataTable - 在RunWorkerCompleted 函数中分配DataTable。在DoWork 内部的循环中,您调用ToString 而不对创建的字符串做任何事情......为什么?
【解决方案2】:

不要忘记阅读 Alexander Petrov 的链接...我发布第二个答案而不是评论您的帖子以突出显示语法...请记住,我无法测试您的代码,但我添加了一些 cmets,前缀为一个**

private void bgnWorker_LoadingForm_DoWork(object sender, DoWorkEventArgs e)
    {
        // TODO: query your database
        // for easier reading I assume that your query-result has only one column
        //string query = @"Select * from dbo.AllInvoicesInReadyStatus";
        //** did you strip your sql-execution-code? have a look at https://msdn.microsoft.com/de-de/library/system.data.sqlclient.sqlcommand.aspx

        var queryResult = new List<object>();
        //queryResult.Add(query);
        bgnWorker_LoadingForm.ReportProgress(10);

        var table = new System.Data.DataTable();
        // TODO: create matching columns for your query-result in the datatable
        // https://msdn.microsoft.com/de-de/library/system.data.datatable.newrow(v=vs.110).aspx
        // Create new DataTable and DataSource objects. 

        // Declare DataColumn and DataRow variables.
        DataColumn column;
        DataRow row;
        DataView view;

        // Create new DataColumn, set DataType, ColumnName, and add to DataTable.    
        column = new DataColumn();
        //** you could write just typeof(string) here...
        column.DataType = System.Type.GetType("System.String");
        column.ColumnName = "invoice";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.String");
        column.ColumnName = "shipment";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.String");
        column.ColumnName = "Project";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.DateTime");
        column.ColumnName = "invoiceDateTB";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.DateTime");
        column.ColumnName = "CreatedDate";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.String");
        column.ColumnName = "typeName";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.String");
        column.ColumnName = "statusName";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.Int32");
        column.ColumnName = "total";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.String");
        column.ColumnName = "import_status";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.DateTime");
        column.ColumnName = "Time_Completed";
        table.Columns.Add(column);

        // Create second column. 
        column = new DataColumn();
        column.DataType = Type.GetType("System.String");
        column.ColumnName = "ERROR_DESCRIPTION";
        table.Columns.Add(column);



        for (var i = 0; i < queryResult.Count; i++)
        {
            var progress = 10 + (int)((float)i / queryResult.Count) * 90;
            bgnWorker_LoadingForm.ReportProgress(progress);

            row = table.NewRow();
        //** dont know whats going on here
        //** but normally you should iterate your data-reader here and transfer the data of your query result to the created row... like this: https://msdn.microsoft.com/de-de/library/haa3afyz(v=vs.110).aspx
            row["invoice"] = i;
            row["shipment"] = "shipment" + i.ToString();
            row["Project"] = "Project" + i.ToString();
            row["invoiceDateTB"].ToString();
            row["CreatedDate"].ToString(); ;
            row["typeName"] = "typeName" + i.ToString();
            row["statusName"] = "statusName" + i.ToString();
            row["total"].ToString();
            row["import_status"] = "import_status" + i.ToString();
            row["Time_Completed"].ToString(); ;
            row["ERROR_DESCRIPTION"] = "ERROR_DESCRIPTION" + i.ToString();

            table.Rows.Add(row);

            // TODO: add the row data to the table
            // same link as before: https://msdn.microsoft.com/de-de/library/system.data.datatable.newrow(v=vs.110).aspx
        }

        //**begin: move this stuff to worker completed
        // Create a DataView using the DataTable. 
        view = new DataView(table);

        // Set a DataGrid control's DataSource to the DataView.
        dataGridView_ShowAllData.DataSource = view;
        //**end

        e.Result = table;
    }

【讨论】:

  • 听起来我会审查并测试它并告诉结果谢谢。
  • 试过我仍然收到以下错误 InvalidOperationException is unhandled by user code Cross-thread operation not valid: Control 'dataGridView_ShowAllData' 从创建它的线程以外的线程访问。
  • @AndresBryan29 请使用您当前的代码更新您的第一篇文章,以便我们了解发生了什么...请包括所有三个 BackgroundWorker 函数:DoWork、ProgressChanged 和 RunWorkerCompleted
  • 我将添加当前代码,以便您查看我遇到的问题
  • 我添加了更新代码,请查看并告诉我。
猜你喜欢
  • 2018-02-27
  • 2014-02-27
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多