从孩子到父母的冒泡事件(总体进展)

时间:2017-09-01 12:12:42

标签: c# events

我有一个问题,我不知道如何解决。 我有一些类(处理器)使用进度信息触发事件(它的距离百分比)。有多个处理器执行此操作,并且调用它们的顶级处理器(引擎)都需要向最终用户发送有关其进度的信息。 如果我事先不知道每个处理器将处理多少项目,我怎样才能给用户一些关于这个过程有多远的好反馈?

看看下面的简化示例

NetFiddle

class Program {
  static void Main(string[] args) {
    var p = new Program();
    p.Run();
  }

  private void Run() {
    var engine = new Engine();
    engine.UpdateProgress += Engine_UpdateProgress;
    engine.Process();


    Console.ReadLine();
  }

  private void Engine_UpdateProgress(object sender, UpdateProgressEventArgs e) {
    Console.WriteLine($"{e.UpdateDateTime} - Caller: {e.Caller}, Percentage: {e.Percentage}");
  }
}

public class Engine {
  private readonly ProcessorA _processorA;
  private readonly ProcessorB _processorB;
  private readonly ProcessorC _processorC;
  private readonly ProcessorD _processorD;

  public event EventHandler<UpdateProgressEventArgs> UpdateProgress;

  public Engine() {
    _processorA = new ProcessorA();
    _processorB = new ProcessorB();
    _processorC = new ProcessorC();
    _processorD = new ProcessorD();

    //Handle events
    _processorA.UpdateProgress += ProcessorA_UpdateProgress;
    _processorB.UpdateProgress += ProcessorA_UpdateProgress;
    _processorC.UpdateProgress += ProcessorA_UpdateProgress;
    _processorD.UpdateProgress += ProcessorA_UpdateProgress;
  }

  private void ProcessorA_UpdateProgress(object sender, UpdateProgressEventArgs e) {
    OnUpdateProgress(e);
  }

  public void Process() {
    _processorA.Process();
    _processorB.Process();
    _processorC.Process();
    _processorD.Process();
  }

  protected virtual void OnUpdateProgress(UpdateProgressEventArgs e) {
    UpdateProgress?.Invoke(this, e);
  }
}

public class ProcessorA : Processor {
  private readonly ProcessorA_A _processorA_A;

  public ProcessorA() {
    _processorA_A = new ProcessorA_A();

    //Handle events
    _processorA_A.UpdateProgress += ProcessorA_A_UpdateProgress;
  }

  public void Process() {
    _processorA_A.Process();
  }

  private void ProcessorA_A_UpdateProgress(object sender, UpdateProgressEventArgs e) {
    OnUpdateProgress(e);
  }
}

public class ProcessorB : Processor {
  public void Process() {

    for (int i = 0; i <= 100; i++) {
      var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorB), Percentage = i, UpdateDateTime = DateTime.Now};
      //Do some work
      Thread.Sleep(r.Next(50,250));
      OnUpdateProgress(args);
    }
  }
}

public class ProcessorC : Processor {
  public void Process() {
    for (int i = 0; i <= 100; i++) {
      var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorC), Percentage = i, UpdateDateTime = DateTime.Now };
      //Do some work
      Thread.Sleep(r.Next(50, 250));
      OnUpdateProgress(args);
    }
  }
}

public class ProcessorD : Processor {
  public void Process() {
    for (int i = 0; i <= 100; i++) {
      var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorD), Percentage = i, UpdateDateTime = DateTime.Now };
      //Do some work
      Thread.Sleep(r.Next(50, 250));
      OnUpdateProgress(args);
    }
  }
}

public class ProcessorA_A : Processor {
  public void Process() {
    for (int i = 0; i <= 100; i++) {
      var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorA_A), Percentage = i, UpdateDateTime = DateTime.Now };
      //Do some work
      Thread.Sleep(r.Next(50, 250));
      OnUpdateProgress(args);
    }
  }
}

public class Processor : IProcessor {
  protected Random r = new Random();
  public event EventHandler<UpdateProgressEventArgs> UpdateProgress;

  protected virtual void OnUpdateProgress(UpdateProgressEventArgs e) {
    UpdateProgress?.Invoke(this, e);
  }
}

public interface IProcessor {
  event EventHandler<UpdateProgressEventArgs> UpdateProgress;
}

public class UpdateProgressEventArgs {
  public int Percentage { get; set; }
  public string Caller { get; set; }
  public DateTime UpdateDateTime { get; set; }
}

只是将进度从孩子发送到父母就不会明显地做到这一点。我希望有人可以帮我找到解决方案。或者,如果有人有另一个出色的解决方案:)

提前致谢

2 个答案:

答案 0 :(得分:3)

引擎可以维护一个私人列表&#34;最后的完整性&#34;每个过程。在字典中很可能。

如果我们扩展你的Engine课程,那就是这个。

private Dictionary<IProcessor, int> _lastReportedPercentage = new Dictionary<IProcessor, int>();

并在定义了所有子处理器的构造函数中,将它们全部设置为0。

public Engine()
{
    //your other stuff
    _lastReportedPercentage[_processorA] = 0;
    _lastReportedPercentage[_processorB] = 0;
    _lastReportedPercentage[_processorC] = 0;
    _lastReportedPercentage[_processorD] = 0;
}
子进程的事件处理程序中的

执行以下操作:

private void ProcessorA_UpdateProgress(object sender, UpdateProgressEventArgs e)
{
    _lastReportedPercentage[(IProcessor)sender] = e.Percentage;
    var totalCompleteness = (int)Math.Floor(_lastReportedPercentage.Values.Sum() / _lastReportedPercentages.Values.Count);
    OnUpdateProgress(new UpdateProgressEventArgs() { Caller = nameof(Engine), Percentage = totalCompleteness, UpdateDateTime = DateTime.Now });
}

然后,您将从引擎中报告所有任务的完整性。

这有一些明显的设计缺陷,但你明白了。如果它们从非构造函数等加载,它可以扩展为可变数量的处理器,但这应该为您提供您想要的所需输出。

答案 1 :(得分:0)

我建议让每个处理器计算完成的项目数量,以及剩余的项目数量。

这样,只要项目完成,以及将项目添加到处理器,引擎就会收到更新。

在Skintkingle的回答中,您将存储引擎内每个处理器的最后一次接收更新。

然后,您可以让引擎决定放置此信息的最佳方式。像完成总数/剩余总数这样简单的东西会运作良好。