【问题标题】:Work with timer and background worker at the same time同时使用计时器和后台工作人员
【发布时间】:2015-12-15 13:20:33
【问题描述】:

我想在计时器滴答事件中调用一个函数,以便它执行直到计时器间隔结束。问题是该函数正在与后台工作人员一起使用,我无法设置 e.Cancel = true 以在时间结束之前停止函数执行。这是我尝试过的。

private void timer1_Tick_1(object sender, EventArgs e)
{
    presenter.RunEngine();    // call the function here
    // ...
}

-------------------------------------------------------

public BackgroundWorker worker;

public PresenterClass()
{
   worker = new BackgroundWorker();
   worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
   worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
   worker.WorkerReportsProgress = true;
   worker.WorkerSupportsCancellation = true;
}

private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
   DisplayState();
}

private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
   if (worker.CancellationPending)
   {
      e.Cancel = true;
      worker.ReportProgress(0);
      return;
   }
   worker.RunWorkerAsync();  // I don't think I should call it here, but it doesn't work otherwise
}

public void RunEngine()
{
   if (worker.CancellationPending)
   {
      view.timer.Enabled = false;
      view.timer.Stop();
      // here I should be able to set e.Cancel = true;
      return;
   }
   double oxygenLevel = _systemEngine.Subsystems.Where(s => s.Article == "Oxygen").First().State.Level;
   if (oxygenLevel > 0)
   {
      ConsumeEngine();
   }
   else
   {
      worker.CancelAsync();
   }
}

private void ConsumeEngine()
{
   Parallel.ForEach(_systemEngine.Subsystems, (currentSystem) =>
   {
      if (currentSystem is ShieldMatrix)
      {
         ConsumeShields(currentSystem);
      }
      else if (currentSystem is WeaponToolbar)
      {
         ConsumeWeapons(currentSystem);
      }
      else {
         currentSystem.State.Consume();
      }
    ));
    worker.ReportProgress(90);
    }

private void ConsumeWeapons(BaseModel currentSystem)
{
   // ...
}

private void ConsumeShields(BaseModel currentSystem)
{
   // ...
}

【问题讨论】:

  • 您的代码不正确。
  • 您能否就我如何使它正确提出一些建议?
  • 你不需要计时器。测量BackgroundWorker 执行期间的时间间隔(使用Stopwatch),看看是否需要等待或在超出给定的循环执行时间跨度时执行特定操作。
  • 你使用后台worker的方式错误太多,不知道怎么下手。请阅读documentation on msdn 如何使用后台工作者。

标签: c# multithreading events timer backgroundworker


【解决方案1】:

我同意其他人的意见,即有更好的方法来实现此功能,但如果您仍将继续使用此方法,那么您需要使 RunEngine 方法可以以某种方式访问​​ DoWorkEventArgs。例如,您可以在调用 RunWorkerAsync 方法之前声明一个实例字段并存储后台工作人员的参数。

    //Declare an instance to store the arguments of the background worker
    public DoWorkEventArgs DoWorkEventArgsIntance { get; set; }


private void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        if (worker.CancellationPending)
        {
            e.Cancel = true;
            worker.ReportProgress(0);

            //Clear the DoWorkEventArgs intance
            DoWorkEventArgsIntance = null;

            return;
        }

        //Set the instance to the current value of the bw
        DoWorkEventArgsIntance = e;

        worker.RunWorkerAsync(); // I don't think I should call it here, but it doesn't work otherwise
    }

然后在 RunEngine 方法上,当您需要停止执行时,您将可以访问参数并且可以调用 Cancel。

public void RunEngine()
    {
        if (worker.CancellationPending)
        {
            view.timer.Enabled = false;
            view.timer.Stop();

            // here I should be able to set e.Cancel = true;

            //As we stored the value before start the worker, now we can cancel here
            DoWorkEventArgsIntance.Cancel = true;

            return;
        }

        double oxygenLevel = _systemEngine.Subsystems.First(s => s.Article == "Oxygen").State.Level;
        if (oxygenLevel > 0)
        {
            ConsumeEngine();
        }
        else
        {
            worker.CancelAsync();
        }
    }

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 2013-10-07
    • 1970-01-01
    • 2020-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-14
    相关资源
    最近更新 更多