c# - 后台 worker 部分或全部更新 ProgressBar 然后炸弹爆炸

标签 c# winforms multithreading progress-bar backgroundworker

不久前,我寻求一些关于设置进度条以向用户显示给定文件和文件夹集的进度的帮助。

看这里:

First Attempt At Background worker.

因此,我设法让它工作,但在某些情况下它会部分填满,有时甚至根本不会填满。退出并出现以下异常?

TargetInvocationException was unhandled .. Exception has been thrown by the target of an invocation.

在我的程序中轰炸到这一行代码。

[MTAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm()); <-- Exception raised at this line !!!
}

它也以绿色突出显示,这是我以前从未见过的。我还尝试将属性也从 STA 更改为 MTA。如果那做某事或没有做某事......那么请告诉。因为我相信它应该由 [MTAThread] 领导。

如果我不报告进度,我的应用程序不会引发错误,但当我这样做时,总是保证会发生。我清理了我的 DoWork 事件处理程序,这样它就不会对定义任何控件(即标签)的线程进行跨线程调用。即使 Albahari.com 告诉我它们不应该工作也不应该存在,但我还是删除了它们。所以我删除了然后坚持这个......它更简单,更干净,更整洁和线程安全显示的重要部分。

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    ...

    for (int i = 0; i < allFiles.Length; i++)
    {
        localSize += allFiles[i].Length;
        // a label used to say   what file is being processed.
        //toolStripStatusLabel.Text = allFiles[i].Name; 
        localFiles++;                
        worker.ReportProgress((100 * i) / allFiles.Length);
    }

    ...
}

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // this event handler is also implemented in my application.
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    fileRetrievalProgressBar.Value = Math.Min(e.ProgressPercentage, 100);
}

以上是我关注的事件处理程序的样子。希望这应该是足够的信息来帮助我,因为我问过的很多人都在这里空白。

我的问题是否与我调用进度条的方式有关,或者与 Invoke()BeginInvoke() 有什么关系......他们是线人。我只是在猜测,但后台工作人员不会自动为您执行此操作。或者这是自动暗示的,我应该回复什么,因为我不知道这什么时候会发生。那么我将不得不做一些类似的事情:

this.Invoke()this.BeginInvoke()

将鼠标悬停在上述两段代码上会显示一个有趣的工具提示,它很有意义,但我正在为如何实现而苦苦挣扎。我相信使用匿名方法吗?我在前面的陈述中使用了下面的示例:

// Takes callbacks from the GetTotalSize() method
private void ProgressCallback(float p)
{
    // Invokes update progress bar on GUI thread:
    this.BeginInvoke(updateProgMethod, new object[] { p });
}

// Actually updates the progress bar:
private void UpdateProgress(float p)
{
    progressBar.Value = (int)(p * (progressBar.Maximum - progressBar.Minimum)) + progressBar.Minimum;
}

感谢名为“Cecil Has A Name”的小伙子!

应该是这样的。期待就我的这个小问题得到一些回应。

最佳答案

首先,您实际上可以使用您已经在使用的ProgressChanged 事件以线程安全的方式更新该状态标签; BackgroundWorker.ReportProgress 有一个重载,它采用一个 object 参数来为此目的传递附加信息。

其次,如果问题是您试图将进度条的值设置为超出最大值,可能是您的硬编码值 100 与进度条的 Maximum 属性(尽管这似乎不太可能,因为我相信 100 是默认值)。

所以我对您的代码的建议更改是:

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < allFiles.Length; i++)
    {
        localSize += allFiles[i].Length;
        localFiles++;

        // this you can pass to ReportProgress
        string statusText = allFiles[i].Name;

        int progressPercentage = (100 * i) / allFiles.Length;
        worker.ReportProgress(progressPercentage, statusText);
    }
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // now that this is being done here, it is thread-safe
    string statusText = e.UserState as string;
    if (!string.IsNullOrEmpty(statusText))
    {
        toolStripStatusLabel.Text = statusText;
    }

    // your progress should be capped at the ProgressBar's Maximum,
    // rather than 100
    int progress = e.ProgressPercentage;
    int maxProgress = fileRetrievalProgressBar.Maximum;
    fileRetrievalProgressBar.Value = Math.Min(progress, maxProgress);
}

关于c# - 后台 worker 部分或全部更新 ProgressBar 然后炸弹爆炸,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1711999/

相关文章:

c# - 如何改变 XNA 中的色调?

c# - "File in use"写入文本文件时出错

c#监听键盘组合

java - 取消/中止/中断 spring-android resttemplate 请求

c# - 如何将文件发送到 com1 端口?

c# - 使用 c# 驱动程序 2.2.3 关闭 mongoDb 服务器

具有相同宽度字符的 C# .NET 多行文本框

android - 如果正在运行的 Activity 关闭, Activity HTTP 调用会发生什么情况?

java - Thread 类的静态 sleep 方法如何在不访问 'this' 引用的情况下工作?

c# - 无法访问的代码 C#