【问题标题】:Background Worker Updating from a different class (preferably via events)后台工作人员从不同的类更新(最好通过事件)
【发布时间】:2013-05-21 19:16:01
【问题描述】:

我的 GUI 类中有一个后台工作者。

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
    ProgressClass obj = new ProgressClass();
    Importer tradeImporter = e.Argument as Importer;
    BackgroundWorker worker = sender as BackgroundWorker;
    List<TradeUploadInfo> list = obj.AllocateTrades2(tradeImporter, false);
    e.Result = list; //Passes the list for processing
}

Importer 是我自己的类。现在,AllocateTrades2 方法完成了所有处理。

我的问题是,如果不将 bw 作为参数传递,我将如何在 AllocateTrades2 方法中执行 bw.ProgressReport ,该方法位于不同的类中?

如果有人向我解释如何处理事件,那就太好了,但如果有另一种优雅的方式。我对想法持开放态度。

【问题讨论】:

    标签: c# winforms events backgroundworker


    【解决方案1】:

    如果您不想传递整个 BGW(这是有道理的)以免暴露超出它需要知道的内容,一种选择是只传递一个您分配了 ReportProgress 调用的委托。

    AllocateTrades2的签名调整为:

    public List<TradeUploadInfo> AllocateTrades2(
        Importer importer, bool flag, Action<int> reportProgress)
    

    从该方法中酌情调用reportProgress 委托。

    然后将调用调整为AllocateTrades2,如下所示:

    obj.AllocateTrades2(tradeImporter, false,
         progress => worker.ReportProgress(progress));
    

    【讨论】:

    • 进度是变量吗?如果是,是什么类型的?诠释?
    • @Alexey 这是该匿名函数的参数。类型是int,是的。它基于在Action&lt;int&gt; 中定义的委托的定义。您可以将那里的类型更改为您想要的任何类型。
    • 我得到一个委托 'System.Func' does not take 1 arguments 错误。
    • @ScottChamberlain Progress 本质上是 BGW 相关方面的替代品。我考虑过提及它,但在这种情况下,他已经在利用 BGW 完成大部分工作。不过,这当然是另一个有效的选择,如果您想完全废弃 BGW(例如,如果使用 TPL),当然值得使用。
    • @Alexey reportProgress(someIntRepresentingTheCurrentProgress)
    【解决方案2】:

    好吧,鉴于AllocateTrades2 在后台工作人员的上下文中运行,它引发的任何事件也会在该上下文中执行。

    因此,您需要做的就是在您的 ProgressClass 中添加一个新事件,例如 NotifyProgress,并将其绑定到您拥有后台工作人员的类。

    所以:

     //In class ProgressClass. 
     public event EventHandler<ProgressClassEventArgs> NotifyProgress = (s, e) => {};
    

    接下来:

     private void bw_DoWork(object sender, DoWorkEventArgs e)
     {
         ProgressClass obj = new ProgressClass();
    
         //Here you hook up the event
         obj.NotifyProgress += this.OnProgressChanged;
    
         Importer tradeImporter = e.Argument as Importer;
         BackgroundWorker worker = sender as BackgroundWorker;
         List<TradeUploadInfo> list = obj.AllocateTrades2(tradeImporter, false);
         e.Result = list; //Passes the list for processing
     }
    

    事件处理程序如下所示:

    private void OnProgressChanged(object sender, ProgressClassEventArgs e) 
    {
       worker.ReportProgress(e.Progress);
    }
    

    没关系,因为您可以(或者您已经这样做)让工人成为此类的成员。

    在这种情况下,您需要定义 ProgressClassEventArgsEventArgs 子类)并添加一个 int 类型的 Progress 属性,以匹配 ReportProgress 参数。

    【讨论】:

      【解决方案3】:

      如果您能够/愿意修改 obj.AllocateTrades2 方法,您可以yield results 然后将每个项目循环添加到您的列表中。

      例子:

      public IEnumerable<TradeUploadInfo> AllocateTrades2(Importer tradeImporter, bool foo)
      {
      
          foreach( ... )
          {
              TradeUploadInfo bar; // = ...
              // ...
              yield return bar;
          }
      
      }
      
      private void bw_DoWork(object sender, DoWorkEventArgs e)
      {
          ProgressClass obj = new ProgressClass();
          Importer tradeImporter = e.Argument as Importer;
          BackgroundWorker worker = sender as BackgroundWorker;
          List<TradeUploadInfo> list = new List<TradeUploadInfo>();
          foreach ( TradeUploadInfo info in obj.AllocateTrades2(tradeImporter, false) )
          {
              list.Add( info );
              // ... progress
          }
          e.Result = list; //Passes the list for processing
      }
      

      这里的美妙之处在于您可以像以前一样使用 AllocateTrades2 (这意味着您不必修改现有代码或重载函数)嗯.. 实际上,您需要修改明确期望 List 的代码,可能只需在函数调用后添加 .ToList() )并且您不需要添加事件(在垃圾收集方面可以得到 a little tricky )。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-21
        相关资源
        最近更新 更多