【问题标题】:C# backgroundworker issueC# 后台工作者问题
【发布时间】:2021-04-02 14:03:07
【问题描述】:

我在 c# 中遇到了 backgroundworker 的问题。 我正在编写一个 dll 文件。

这是我在 VS 2019 中的类库 (.NET Framework) 类型项目中的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace States
{    
    public class ST
    {        
        public static void Read()
        {
            BackgroundWorker bgwMessage = new BackgroundWorker();
            bgwMessage.DoWork += new DoWorkEventHandler(BgwFileOpen_DoWork);
            bgwMessage.RunWorkerAsync();
        }
       
        private static void BgwFileOpen_DoWork(object sender, DoWorkEventArgs e)
        {
            MessageBox.Show("Ran");
        }
    }
}

当我使用 立即 窗口调用 Read() 方法时,后台工作人员的 DoWork 方法中的命令不会运行。逐行调试问题表明Read() 方法正在运行,但它没有以某种方式调用 RunworkerAsync。

*更新1: 启动线程也不起作用:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TradeStates
{
    
    public class ST
    {
        
        public static void Read()
        {
            Thread thr = new Thread(new ThreadStart(MSGshow));
            thr.Start();
        }
        public static void MSGshow()
        {
            MessageBox.Show("Ran");
        }


    }
}

【问题讨论】:

  • 由于 BackgroundWorker 类是 IDisposable,请考虑将其声明移动到一个字段中,然后在工作人员完成后将其处理掉。
  • 嗯,“即时窗口”。即时窗口总是能够显示消息框吗?假设您在调试过程中正在立即窗口中执行命令,请尝试将“MessageBox.Show("Ran")”替换为“Debug.WriteLine("Ran")”并查看输出是否显示在调试中输出窗口的类别。
  • @Julius 如果我将消息框放在“读取”方法中,它将被执行。我试过“Debug.WriteLine”它也没有执行。

标签: c# backgroundworker


【解决方案1】:

我建议使用任务。它适用于 4.5 以上的任何 dotnet(4.0 还带有附加包)

using System.Threading.Tasks;
public class ST
{        
    public static async Task Read()
    {
        await Task.Run(() => {
              //Do some big work here
        };
    }               
}

然后例如在您的按钮单击事件中调用:

private async void Button_Click(object sender, EventArgs e)
{
   await ST.Read();
   MessageBox.Show("Ran");
}

这不会在您执行大型读取任务时冻结您的视图,并且会在完成后返回到 Button_Click 函数的下一行以显示对话框结果。
您甚至可以在 Read 调用之前添加一些代码来警告用户后台正在发生某些事情:)

【讨论】:

    【解决方案2】:

    一些事情......

    正确实现后台工作器

    DoWork 事件被触发一次以执行后台工作,并且不得执行任何访问 UI 控件/UI 线程的操作。

    您还可以使用另外两个事件。 ProgressChanged 用于报告进度。例如,您可以实现该方法来更新进度条。另一个,我认为你应该感兴趣的一个是RunWorkerCompleted。在你的情况下,你会有类似的东西

    bgwMessage.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(BgwFileOpen_ShowDialog);
    ...
    private void BgwFileOpen_ShowDialog(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("Ran");
    }
    

    其他一些想法

    • 您的后台工作人员通常应该是Form 或其他winforms 类的属性,因为BackgroundWorker 继承自Component。
    • 当后台worker的parent被释放时,它应该调用后台worker上的Dispose()。

    BackgroundWorker Class 文档提供了如何正确使用该类的一个很好的示例。

    改用线程或任务

    如果您必须从Read() 创建和启动worker,我建议您改为启动Thread,并让它在完成后向UI 线程发送一条消息。然后,您的消息处理程序将启动消息框。

    您甚至可以使用Task,然后向在UI 线程上继续的任务添加一个延续,调用MessageBox.Show()。

    即时窗口问题

    It appears 即时窗口可能在执行线程或至少显示其他线程的输出/结果时出现问题,而不是它正在运行的线程。它旨在与您(开发人员)进行交互,而不是作为运行应用程序的全功能环境,例如 winforms。

    我相信如果你设计你的Read() 方法来接受一个正确实现的后台工作程序(即在Read() 之外创建和设置),然后在Read() 内调用RunWorkerAsync(),消息框应该会按预期弹出 - 只是您在通过即时窗口时不会看到它。

    【讨论】:

    • 感谢您在第一阶段的回复。我还尝试了“线程”方法。但它也没有运行。我编辑了最初的问题并包含了我的第二次尝试。
    • 和 BackgroundWorker 一样,你不能在非 UI 线程中调用 MessageBox.Show()。
    • 可能抛出了异常,并且不知何故即时窗口没有捕获/显示异常......您是否尝试过正常运行代码以查看它是否正确执行?如果是这样,我什至不会担心它不会出现在“即时”窗口中。
    猜你喜欢
    • 1970-01-01
    • 2011-09-04
    • 2011-10-30
    • 2011-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多