未调用 BackgroundWorker DoWork 函数

Posted

技术标签:

【中文标题】未调用 BackgroundWorker DoWork 函数【英文标题】:BackgroundWorker DoWork function is not being called 【发布时间】:2021-01-03 00:57:27 【问题描述】:

我在我的 C# WinForms 应用程序中创建了一个加载表单,该表单在长流程中显示。 我在我的加载表单中添加了一个进度条,我想更新它以向用户提供一些加载反馈。

在我的加载表单代码中,我创建了一个新的 BackgroundWorker 并添加了 DoWork 和 ProgressChanged 事件处理程序。 问题是没有调用 backgroundWorker_ProgressChanged。我在函数中插入了断点,它们没有被捕获。

我哪里错了?任何帮助表示赞赏。谢谢。

frmLoading:

public frmLoading()
        
            InitializeComponent();

            //check if bg worker is null
            if (backgroundWorker == null)
            
                backgroundWorker = new BackgroundWorker();

                backgroundWorker.DoWork += backgroundWorker_DoWork;
                backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;

                
            

            backgroundWorker.WorkerReportsProgress = true;

            //start
            backgroundWorker.RunWorkerAsync();
        

backgroundWorker_DoWork:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        
            for (int i = 1; i <= 100; i++)
            
                Thread.Sleep(100);
                backgroundWorker.ReportProgress(i);
            
        

backgroundWorker_ProgressChanged:

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        
            //update value of progress bar
            progressBar1.Value = e.ProgressPercentage;
            //set the text of the progress bar
            this.Text = e.ProgressPercentage.ToString();
        

【问题讨论】:

使用调试器,Debug > Windows > Threads,观察主线程在做什么。它必须处于空闲状态,在 Application.Run() 中执行才能执行此事件处理程序。永远不要让它执行昂贵的代码,这是工作线程的工作。 BGW 自 2012 年以来已过时,完全被 Task.Run 和 Progress 取代。不过,要定期更新 UI,您只需要a Timer,而不是后台线程。创建一个简单的 Winforms 计时器,在加载时启用它并在完成后禁用它,或者当 ProgressBar 达到最大值时禁用它 谢谢,我会看看 Task.Run。我认为这项工作需要在一个单独的线程上进行,因为我已经在另一个表单的后台运行了大型进程。 @PaulAlexander - Task.Run 将在另一个线程上执行。 为什么要检查backgroundWorker == null?当然是null,你在表单的构造函数中。除非那里发生了您没有显示的其他事情,例如尝试以某种方式回收此表单。将backgroundWorker.RunWorkerAsync(); 移动到Form.LoadForm.OnLoad(或OnShown() 以查看表单是否显示已呈现)。如果它没有启动,那么你不会让它启动,因为其他东西阻塞了 UI 线程,所以这行代码永远不会执行。 【参考方案1】:

以下是使用 Progress&lt;int&gt;Task.Run 的方法:

public frmLoading()

    InitializeComponent();

    IProgress<int> progress = new Progress<int>(p =>
    
        //update value of progress bar
        progressBar1.Value = p;
        //set the text of the progress bar
        this.Text = p.ToString();
    );

    Task.Run(async () =>
    
        for (int i = 1; i <= 100; i++)
        
            await Task.Delay(TimeSpan.FromSeconds(0.1));
            progress.Report(i);
        
    );


我个人更喜欢微软的响应式框架:

public frmLoading()

    InitializeComponent();

    Observable
        .Interval(TimeSpan.FromSeconds(0.1))
        .Take(100)
        .ObserveOn(this)
        .Select(p => p + 1)
        .Subscribe(p =>
        
            //update value of progress bar
            progressBar1.Value = p;
            //set the text of the progress bar
            this.Text = p.ToString();
        );

【讨论】:

以上是关于未调用 BackgroundWorker DoWork 函数的主要内容,如果未能解决你的问题,请参考以下文章

多个并行未定义的BackgroundWorker [重复]

c# 关于backgroundWorker的取消

QT5 插槽未在子类中调用

C# backgroundworker使用方法

BackgroundWorker使用秒表更新经过的时间标签,由于调用C#而冻结[重复]

BackgroundWorker 异常处理