【问题标题】:BackgroundWorker's progress bar is not workingBackgroundWorker 的进度条不起作用
【发布时间】:2018-10-19 04:11:07
【问题描述】:

BackgroundWorker 的进度条在执行某些任务时不会更新。我想要达到的是进度条在遍历 DirectoryInfo 中的每个文件时移动。假设我们有 20 个“.sql”文件,而第一个文件完成时应该是 5%、10% 等等。 这是我的代码。

private void CSV_Click(object sender, RoutedEventArgs e)
        {         
            try
            {
                btnExtract.IsEnabled = false;
                workerextract.RunWorkerAsync();

        }
        catch (Exception ex)
        {
            System.Windows.MessageBox.Show(ex.Message);
        }
    }

    private void workerextract_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        try
        {
           this.Dispatcher.Invoke(() =>
            {

                DirectoryInfo di = new DirectoryInfo(txtQueryfolder.Text);
                files = di.GetFiles("*.sql").Count();
                currentfile = 0;

                foreach (FileInfo fi in di.GetFiles("*.sql"))
                {
                    // Open the text file using a stream reader.
                    using (StreamReader sr = new StreamReader(fi.FullName))
                    {
                        // Read the stream to a string, and write the string to the console.
                        string line = sr.ReadToEnd();

                        //System.Windows.MessageBox.Show(line);
                        ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name));
                        currentfile++;
                    }
                    int percentage = (currentfile + 1) * 100 / files;
                    workerextract.ReportProgress(percentage);
                }

            });

        }
        catch(Exception ex)
        {
            System.Windows.MessageBox.Show(ex.Message);
        }
    }

    private void workerextract_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
    {
        progressBarExtract.Value = e.ProgressPercentage;
    }

    private void workerextract_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        btnExtract.IsEnabled = true;
        System.Windows.MessageBox.Show("CSV Data extraction finished!");
    }

我发现了

private void workerextract_ProgressChanged(对象发送者, System.ComponentModel.ProgressChangedEventArgs e)

在 100% 结束时调用一次。 还有,

private void workerextract_RunWorkerCompleted(对象发送者, RunWorkerCompletedEventArgs e)

从来没有打电话,因为我没有看到最后的消息框。

所以,我认为我在这里做错了什么,请您指导我正确的方式吗?

【问题讨论】:

  • 为什么会被多次调用?您只报告一次进度 - 最后。您根本没有报告循环中的进度。
  • 我已经修改了我的代码,即使在循环内部也只调用了一次。
  • 您全力以赴创建一个后台工作线程 - 然后要求Dispatcher 将您的大部分代码返回 移到 UI 线程上。你为什么要这么做?
  • 所以停止从后台工作代码访问 UI 对象。或者,如果您“必须”访问 UI 对象,只需用 Dispatcher.Invoke 包裹 那些行,而不是 整个 循环。
  • 你为什么要生成一个后台工作者只是为了在 UI 线程上运行它??? this.Dispatcher.Invoke。这违背了整个目的

标签: c# backgroundworker


【解决方案1】:

问题在于将整个 DoWork 包装在 Dispatcher.Invoke 中。 我只需要包装与 UI 交互的那些代码。 所以我适当地更改了代码并且它可以工作。

 private void workerextract_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            try
            {
                this.Dispatcher.Invoke(() =>
                {
                    di = new DirectoryInfo(txtQueryfolder.Text);
                });
                    files = di.GetFiles("*.sql").Count();
                    currentfile = 0;

                foreach (FileInfo fi in di.GetFiles("*.sql"))
                {
                    // Open the text file using a stream reader.
                    using (StreamReader sr = new StreamReader(fi.FullName))
                    {
                        // Read the stream to a string, and write the string to the console.
                        string line = sr.ReadToEnd();

                        this.Dispatcher.Invoke(() =>
                        {
                        //System.Windows.MessageBox.Show(line);
                        ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name));
                        });

                        currentfile++;
                    }
                    int percentage = (currentfile + 1) * 100 / files;
                    workerextract.ReportProgress(percentage);
                }
        }
        catch(Exception ex)
        {
            System.Windows.MessageBox.Show(ex.Message);
        }
    }

感谢大家指路。

【讨论】:

  • 这不是正确的方法,即使它有效。请看看我更新的答案。另外,ExtractToCSV 的代码是?为什么要访问 UI 对象?
  • @OmarMuscatello 请在您的答案下方查看我的评论
【解决方案2】:

BackgroundWorkerDoWork 事件中使用this.Dispatcher.Invoke,您正在UI 线程中执行整个操作;这是BackgroundWorker生来就避免做的事情。

此外,由于您正在访问一个 UI 对象,即txtQueryfolder,因此您在从调度程序中解包代码时会遇到错误。

只需使用:

private void workerextract_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    string queryFolder = e.Argument.ToString();
    try
    {
        DirectoryInfo di = new DirectoryInfo(queryFolder);
        files = di.GetFiles("*.sql").Count();
        currentfile = 0;

        foreach (FileInfo fi in di.GetFiles("*.sql"))
        {
            // Open the text file using a stream reader.
            using (StreamReader sr = new StreamReader(fi.FullName))
            {
                // Read the stream to a string, and write the string to the console.
                string line = sr.ReadToEnd();

                //System.Windows.MessageBox.Show(line);

                // ExtractToCSV shouldn't access to a UI object.
                ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name));
                currentfile++;
            }
            int percentage = (currentfile + 1) * 100 / files;
            workerextract.ReportProgress(percentage);
        }
    }
    catch (Exception ex)
    {
        // Don't use MessageBox in a thread different from the UI one. Just set the result (e.Result) and get that in the RunWorkerCompleted event.
        // System.Windows.MessageBox.Show(ex.Message);
    }
}

当您调用RunWorkerAsync 方法时,只需添加如下参数:

workerextrac.RunWorkerAsync(txtQueryfolder.Text);

【讨论】:

  • 行ExtractToCSV(line, System.IO.Path.GetFileNameWithoutExtension(fi.Name));给出错误“调用线程无法访问此对象,因为不同的线程拥有它。”
  • 您应该发布ExtractToCSV函数的代码以获得帮助,或者只是尝试评论该函数的内容,看看它是否正常工作;只是调试它:)
  • 是的,如果我对 ExtractToCSV 进行评论,它会起作用,我刚刚用 Dispatcher 包装。调用该部分,似乎一切都很好,感谢您的帮助。
  • @FirdavsKurbonov,很高兴为您提供帮助。我很高兴你明白了,但是,这不应该是正确的解决方案 AFAIK。迭代和执行ExtractToCSV 函数是该方法的耗时部分。所有部分都应在后台线程中执行。但是,只是一个提示:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多