【问题标题】:C# event bubblingC# 事件冒泡
【发布时间】:2011-11-08 20:32:37
【问题描述】:

我在实现以下目标时遇到了一些麻烦:

Form1 有两个按钮“Validate”和“Cancel”,还有一个BackgroundWorker。 Class1 处理方法繁重。

点击“Validate”调用DoWork,繁重的工作是Class1的一个方法。我已经设法“监听”了我的 DoWork 中由 Class1 方法引起的进度更改事件。

现在,当单击“取消”按钮时,我正在尝试取消繁重的任务(在方法内部)。

private void buttonCancelValidation_Click(object sender, EventArgs e)
    {
        backgroundWorker.CancelAsync();
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        Class1 obj = new Class1();
        obj.ProgressChanged += (s, pe) => backgroundWorker.ReportProgress(pe.ProgressPercentage);

        //---> Here a i'm trying to "tell" class1 that if the "Cancel" button was clicked then I want to abort ASAP the HeavyMethod operation.

        obj.HeavyMethod();

        //followed by the cancel of BackgroundWorker DoWork
        if (backgroundWorker.CancellationPending  
        {
            e.Cancel = true;
        }
    }

感谢您的帮助!

【问题讨论】:

  • @Charles 如何从 FORM1 告诉另一个类对象方法单击了取消。

标签: c# winforms events backgroundworker


【解决方案1】:

在不知道 HeavyMethod 的工作原理的情况下,唯一的方法是让线程等待 HeavyMethod 完成,或者提供一种从 obj 类中中断 HeavyMethod 的方法。

您可以让 Class1 接受对 backgroundWorker 对象的引用,以便 HeavyMethod 可以检查 CancellationPending 标志的值并中断该方法。这只有在您的 HeavyMethod 有一个循环或一组较小的任务时才有效,您可以在其中检查任务之间的此标志,以便尽早中断或从该方法返回。

你可以这样做

public class Class1
{
   private BackgroundWorker _backgroundWorker = null;
   public Class1(BackgroundWorkerThread worker)
   {
     _backgroundWorker = worker;
     // rest of constructor
   }

   public void HeavyWorker()
   {
      // Heavy work

      // Have we been cancelled.
      if (_backgroundWorker != null && _backgroundWorker.CancellationPending)
      {
         // perform clean up and return
      }

       // Perform more heavy work.
   }
} 

private void backgroundWorker_DoWork(...)
{
   Class1 obj = new Class1(backgroundWorker);

   obj.HeavyMethod();
}

【讨论】:

  • 我只是在一个循环中读取 HeavyMethod 中的文件,因此我可以在该循环中中止它。如果这是您的选择,您会选择第一个解决方案还是第二个解决方案?我想我在某处读到将 BGW 传递给另一个类对象不是一个好主意。
  • 我不记得读过任何关于将 BGW 传递给另一个类对象的问题,只要该对象仅在执行 backgroundWorker 期间存在。因为一旦线程完成工作,引用了 worker 的对象就应该被处理掉。当您开始获取对陈旧后台工作人员的引用时,就会出现此问题。而且我只是把上面看到的检查放在循环中,如果你被取消,不要忘记关闭文件。
  • 我会尝试找到它以确保我不会弄乱概念。所以这是完美的,将使用这个已经在另一个项目中使用过的解决方案,但实际上我有点不确定这种方法!谢谢!
【解决方案2】:

您的HeavyMethod() 代码必须能够访问一些(比如说布尔)变量,该变量应该指示它是否需要立即返回。您在HeavyMethod() 代码中检查该变量值的频率将改变用户单击“取消”按钮和操作实际停止之间的延迟。

bool cancelValidationRequest = false; 
private void buttonCancelValidation_Click(object sender, EventArgs e)
    {
        cancelValidationRequest = true; // this will cause HeavyMethod return asap
        backgroundWorker.CancelAsync(); // this makes requet to thread to stop, but it still in HeavyMethod...
    }

HeavyMethod()里面

private void HeavyMethod() 
{   

    //execute heavy code 
    if(cancelValidationRequest ) return; 

   // continue execute heavy code 
    if(cancelValidationRequest ) return; 

   ..... 
   ....
}

类似这样的东西,只是为了提供一个想法。

编辑

正如 Wizetux 所指出的,您必须注意布尔值(在这种特定情况下)由不同的线程操作这一事实。

希望这会有所帮助。

【讨论】:

  • 正如他所说,您需要定期检查终止请求:msdn.microsoft.com/en-us/library/7a2f3ay4(v=vs.80).aspx
  • 由于您将从两个不同的线程设置和获取 bool 的值,因此您将不得不担心此任务的线程安全,以免您最终陷入比赛条件。我相信 backgroundWorker 对象会在内部执行此操作。
  • @Tigran 哈哈,这很容易......呵呵。 Obj 在 DoWork 中被实例化,因此在 ButtonCancelValidation 中是未知的。可以将 cancelValidationRequest 设置为 Class1 中的静态属性吗?做了一个快速测试,没关系。
  • @Libas:我建议使用成员变量。看看这个:geekswithblogs.net/chrishan/archive/2005/11/04/59102.aspx
  • @Tigran 这样做,obj应该是Form1中的一个字段,不要太喜欢这个。感谢您指出这个问题!想我会去第二个 Wizetux 解决方案
猜你喜欢
  • 1970-01-01
  • 2011-01-30
  • 2011-10-20
  • 2011-08-23
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多