【问题标题】:Add a progress bar while the a table is being load it to the DataGridView In C#在将表加载到 C# 中的 DataGridView 时添加进度条
【发布时间】:2018-02-27 17:35:45
【问题描述】:

在加载 datagridview 时,我需要一些帮助来添加进度条。我已经有了加载 datagridview 的代码,但我们知道加载需要时间来完成加载,具体取决于记录。所以,我想添加一个进度条加载和一个计数从 1 到 100 的标签来完成。

我知道有一种使用后台工作句柄事件的方法,但不确定它是如何工作的。我想要一些简单但可以完成我需要的工作。

我的代码效果很好,可以根据需要填充 datagridview。但我需要在加载 datagridview 时添加进度条。

更改代码请查看并告诉我是否遗漏了什么。

所以我进行了更改,现在似乎可以工作,但是有一个问题是进度条不能立即工作,需要几秒钟,然后我可以看到进度条移动到 100%。为什么这样做?

加载 datagridview 后的第二个问题,当我单击消息 MessageBox.Show("Successful Completion."); 后,进度条颜色消失了;

这是我的组合框选择我们想要的值并显示数据网格视图后的测试图像

在这里我对程序进行了新的更改,但由于某种原因,在我选择了组合框后,datagridview 会正确填充,但是我有时会再试一次它会失败并给我这个错误

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

【问题讨论】:

  • 如果您不希望进度条在最后消失,请删除将值设置为 0 的行。progressBar_GetTasks.Value = 0
  • 声明一个新变量:int progress;for 循环中添加两行:progress = i * 100 / dt.rows.count; dbWorker.ReportProgress(progress);
  • 最新的错误是因为你没有移动GetTableToDataGridView()函数调用...你已经复制了!在您的事件处理程序 comboBox_Database_SelectedIndexChanged 中,删除 GetTableToDataGridView() 行。否则,您将启动一个新线程来进行处理,以及在主线程上进行处理。有时你会很幸运,这两个过程会重叠。有时你不会那么幸运,其中一个进程会先完成,你会得到一个异常。
  • 没关系,你是对的,谢谢兄弟的帮助!!!!学到了很多。一切正常,我相信,如果不是,我会回复你。谢谢。 @PeterAbolins。

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


【解决方案1】:

首先,SELECT * 是个坏主意,无论您拥有或需要多少列。明确说明您想要哪些列为使用索引开辟了可能性,并减少了代码的可维护性问题。

其次,您的主要问题。我最近也做过类似的事情,可以指点一下。我不会立即将它应用到您的 code-sn-p,因为我认为这会使事情复杂化。

编辑

出于线程安全的目的,dbWorker_DoWork() 中的代码不应尝试访问在主线程中创建的表单元素。显然有很多方法可以解决这个问题,一旦你到达dbWorker_RunWorkerCompleted() 函数,你就回到了主线程,你可以完全访问必要的表单元素。

结束编辑

1) 你的表格。您需要一个后台工作人员来完成这项工作,以及三个回调函数来处理正在发生的事情。进度条也假定在表单上 (System.Windows.Forms.ProgressBar)。

...
using System.ComponentModel;
...
public partial class YourForm : Form
{
    BackgroundWorker dbWorker;
    ...
    public YourForm()
    {
        ...
        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;
        ...
    }
    ...
    public void dbWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        // This is where you put your GetTableToDataGridView() code.
        // Add a line inside the loop, for reporting on progress:

        // dbWorker.ReportProgress((int)(currentIteration * 100 / totalIterations));

        // At the end of the process, set the progress bar to 100% (optional)
        dbWorker.ReportProgress(100);
    }

    public void dbWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;

        // Here you can also do other things, which depend on the progress. 
        // eg: Set your label text to the current value of the progress bar.
    }

    public 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
        {
            MessageBox.Show("Successful Completion.");
        }

        progressBar.Value = 0;
    } 
}

2) 启动流程(这可以在您的表单加载功能中进行,或者如果您手动启动该流程,则在 OnClick 事件中):

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

3) 取消进程(如果你有一个取消按钮,那么这将进入OnClick 事件代码):

...
if (dbWorker.IsBusy)
{
    dbWorker.CancelAsync();
}
... 

【讨论】:

  • 我对程序进行了更改,如果我遗漏了任何内容,请查看上面的内容。我还添加了一个错误,我得到的是图像
  • 您需要将分配到数据网格,从DoWork 进程移动到RunWorkerCompleted 进程。这可以通过扩展 dt 对象的范围(将变量移到函数外,以便 DoWork 进程和 RunWorkerCompleted 进程都可以访问),然后在 DoWork 中填充 dt 并在 RunWorkerCompleted 中填充网格来完成。
  • 我做了上面的更改,您可以查看一下图片吗
  • 如果上述答案对您最初的问题有所帮助,也许您可​​以将其标记为答案?展望未来,一个提示是让错误对你有用,而不是对你不利:当错误消息出现时谷歌它。 10 次中有 9 次,您的问题的答案将是最先返回的结果之一。
【解决方案2】:

几个明显的问题:

  • 由于您在 using 块内有连接,因此不需要显式的 conn.Close()。即使发生异常,using 机制也会自动关闭它。实际上,除非您需要在此级别处理异常,否则您可以完全删除 try 块。

  • 永远不要使用SELECT *。您正在检索大量不需要的数据,这可能是它最初运行缓慢的原因。

直截了当地问:BackgroundWorker 是你的朋友!

我更熟悉使用 WPF 进行数据绑定,因此您需要自己做一些跑腿工作。但基本思想是,您将进度条的可见性绑定到一个变量,然后更新该变量:

  • 当您启动线程时,使其可见(使用 IsIndeterminate 属性很有用,因为没有真正的方法来为 SQL 查询计算百分比)
  • 当线程结束时,隐藏进度条。

通过这种方式,您可以在查询运行时获得动画进度条。

你可以用同样的方法将鼠标光标设置为忙/箭头。

【讨论】:

  • 我使用 select * 的原因是因为这些列只有 12 列,我已经在 for 循环中应用了这些列。该表中没有其他列。因为你只是 WPF 的经验。有没有其他人可以帮助我解决我的问题。我需要可以帮助处理 C# windows 窗体的人。
猜你喜欢
  • 2014-02-27
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多