【问题标题】:C# Backgroundworker keep on running DoWorkC# Backgroundworker 继续运行 DoWork
【发布时间】:2023-03-03 02:23:01
【问题描述】:

下面是我的代码:

    Form2 msgForm;
    private void button3_Click_1(object sender, EventArgs e)
    {

        bw.WorkerReportsProgress = true;
        bw.WorkerSupportsCancellation = true;
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

        msgForm = new Form2();

        try
        {
            bw.RunWorkerAsync();

            msgForm.ShowDialog();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        // Coding that transmit protocol and will last around 2 minutes.
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        msgForm.Close();
    }

每次单击按钮时,我都会使用后台工作程序方法来传输持续约 2 分钟的协议。在传输过程中,From2 将显示“请稍候”。

但是我在使用这种编码时遇到了一些问题。问题是,当我第一次单击按钮时,它会传输一次协议。之后我再次单击,这是第二次,它传输了两次协议。之后我再次点击,这是第三次,它传输协议3次......等等。每次点击按钮,传输协议的次数都会增加。

不是说每次点击按钮都只会运行一次void bw_DoWork中的编码吗?

我的编码有问题吗?

【问题讨论】:

    标签: c#


    【解决方案1】:

    您每次单击时都会添加一个 附加 处理程序,然后它会与您之前添加的所有内容一起运行,它会保持原样(因为对象是还在那里,你在重复使用它)。

    要解决这个问题,您需要:

    • 将后台worker的声明移到方法中(所以每次都是新的,只有一个DoWork处理程序

    像这样:

    private void button3_Click_1(object sender, EventArgs e)
    {
        BackgroundWorker bw = new BackgroundWorker();
        // rest of your code
    }
    
    • 移动.DoWork += ...,它在类的构造函数中附加处理程序

    这主要取决于您是否在其他地方使用该工人。

    【讨论】:

    • 没有亚历克斯。我只是在传输协议中使用worker。
    • 然后在方法里面声明。
    • Alex,你把后台worker的声明移到方法里面是什么意思?
    • 他说你每次点击都在做bw.DoWork += new DoWorkEventHandler(bw_DoWork)。你不应该。您应该只执行一次 +=。
    • 如果你想每次点击一次,然后先取消链接旧的处理程序:bw.DoWork -= new DoWorkEventHandler(bw_DoWork); bw.DoWork += new DoWorkEventHandler(bw_DoWork); 但在你的情况下它是没有意义的。如果它根本没有改变,你不需要一次又一次地附加处理程序。
    【解决方案2】:

    看起来每次点击都会启动一个新的工作人员。 为避免这种行为,请在重新启动之前检查工作人员是否正忙。

    try
    {
        if (!bw.IsBusy)
            bw.RunWorkerAsync();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    

    您可以在后台工作人员执行其工作时禁用该按钮,通过button3.Enabled = false; 并在bw_RunWorkerCompleted 方法中重新启用它,让用户了解他必须等待并且在该过程完成之前不能再次单击。

    【讨论】:

    • 不。他每次都在附加另一个处理程序。
    • @Alex 我仔细检查了这个问题,你是对的,我错过了这一点。赞成你的答案。无论如何,我认为检查 BackgroundWorker 是否已经在运行并相应地启用/禁用按钮是个好主意 =)
    【解决方案3】:

    首先确保您的列表/收藏在传输代码之前是清晰的。 然后在你的源代码中使用 BreakPoint 并记住你的 BackgroundWorker 不能运行两次或更多次,因为你使用了 ShowDialog。

    【讨论】:

      【解决方案4】:

      检查worker是否忙:

          if (!bw.IsBusy)         
          bw.RunWorkerAsync(); 
      

      在执行过程时,我还会禁用按钮并将文本更改为例如“正在运行”。

      使用 bw_RunWorkerCompleted 方法事件调用,然后重新启用按钮并更改文本。此方法与 UI 在同一线程上运行,因此不存在跨线程问题。

      在您的设计中,为什么要显示“请稍候”通知的另一个表单?我建议在异步进程开始之前更新现有表单上的标签(因此不会出现跨线程 UI 问题),或者如果您需要在之后更新,则可以使用以下内容:

      lblNotify.Invoke(new Action(() => lblNotify.Text = @"Please wait"));
      

      然后上面将允许您在主线程上运行您的请求。

      【讨论】:

        猜你喜欢
        • 2013-11-15
        • 1970-01-01
        • 2013-07-29
        • 2021-01-03
        • 2013-05-24
        • 1970-01-01
        • 2012-03-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多