0

我有一个关于后台工作人员如何实际工作的问题。我不太确定它如何使用不同的方法。

因此,例如,我有以下代码(出于说明目的,改编自http://broadcast.oreilly.com/2010/06/understanding-c-using-backgrou.html ):

private void getDateTime()
{
    DateTime startTime = DateTime.Now;
    double value = Math.E;
    while (DateTime.Now < startTime.AddMilliseconds(100)) 
    {
      value /= Math.PI;
      value *= Math.Sqrt(2);
    }
}

private backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    for(int i=0; i <= 100; i++)
    {
        getDateTime();
        backgroundWorker1.ReportProgress(i);
    }
}

这将使用后台工作线程不断计算 DateTime。现在我假设 backgroundworker 的 DoWork 方法中的 for 循环将运行计算,报告进度,然后重复循环(如果我误解了,请纠正我)。

现在假设我有另一种方法,它解析一个(可能很大)DataTable并返回另一个DataTable,在后台使用它意味着我会一遍又一遍地解析DataTable(理论上。再次,如果我错了,请纠正我) ? 如果这是程序的流程,是否有更有效的方法来实现 DataTable 解析而无需重复循环,但仍然能够使用 backgroundworker?

这适用于 Windows 窗体,当我解析 DataTable(s) 时,UI 往往会冻结。我听说 backgroundworker 可以帮助我解决 UI 的冻结问题,但我发现必须一遍又一遍地重新解析整个 DataTable 效率非常低。但是,我不确定是否有任何其他方式可以在没有 for 循环的情况下报告进度。

编辑:

我想出了一个临时解决方案。它有效,但我仍然无法报告进度。

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        int rows = (int)e.Argument;
        int count = 0;
        t3 = runComparison();
        for (int i = 0; i <= rows; i++)
        {
            count++;
            int current = count / rows;
            backgroundWorker1.ReportProgress(current * 100);
        }
        e.Result = t3;
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            MessageBox.Show("An unexpected error has occurred. Please try again later.", "ERROR!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            dataGridView1.DataSource = e.Result;
        }
    }

我知道我的 for 循环没有做任何事情。但是,“runComparison”已经消耗了很多时间。因此,如果它在 for 循环中,则直到整个运行过程才会报告进度。或者,也许我可以使用标签或消息框而不是进度条。不太确定我应该如何实现这一目标。

4

2 回答 2

1

尝试这样做:

//make sure background worker report progress
backgroundWorker1.WorkerReportsProgress = True;


private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
    progressBar1.Refresh;
    //if your progressbar is on a status strip, you need to refresh the status strip instead
}
于 2012-10-16T08:06:11.590 回答
1

我想出了一个相当不雅的解决方案。但它满足用户友好性的要求,所以......无论什么工作:P

感谢所有的反馈,我很感激。

无论如何,这是代码:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        backgroundWorker1.ReportProgress(1); //to invoke ProgressChanged
        t3 = runComparison(); //run intensive method
        e.Result = t3; //return DataTable
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Visible = true; //display a label
        textBoxProgress.Visible = true; //display the progress bar
        //change the progress bar style
        //the Marquee style is constantly running, so it could show users the process is working
        //not too sure how to explain it, you'll have to try it out. 
        progressBar1.Style = ProgressBarStyle.Marquee; 
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            MessageBox.Show("An unexpected error has occurred. Please try again later.", "ERROR!", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
            //reset the display and update the DataGridView
            progressBar1.Visible = false;
            textBoxProgress.Visible = false;
            progressBar1.Style = ProgressBarStyle.Blocks;
            dataGridView1.DataSource = e.Result;
        }
    }
于 2012-10-16T09:03:15.607 回答