从子组件向父组件传递事件(整体进度)

3
我有一个问题,不知道该怎么解决。 我有一些类(处理器),会触发带有进度信息的事件(完成百分比)。有多个处理器执行此操作,顶层处理器(引擎)调用它们所有的进程,并需要向最终用户发送其进度信息。 如果我事先不知道每个处理器要处理多少项,我如何向用户提供关于进程进展的良好反馈?
请看下面的简化示例 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; }
}

仅仅将进度从子组件发送到父组件显然行不通。希望有人能帮我找到解决方案。或者如果有其他聪明的解决方案 :)

提前感谢


1
如果您不知道应该做什么和做多少,可以更新一下您的进度。为什么处理器不知道它应该做多少事情呢? - Jeroen van Langen
取决于你想要多细致。引擎知道它有多少处理器。而且它可能知道有多少处理器的进度达到了100%或更低。因此,你的引擎进度可以简单地是100%处理器的数量...或者是添加的百分比/处理器数量。 - Fildor
你需要为所有子事件添加处理程序,这样你才能知道有多少个处理器正在运行,因此你的总完整度为100 *(进程数)。“总完整度”应该是父级向任何正在监听它的对象报告的吗?这不是你想要的吗? - Skintkingle
1
如果处理器应该处理一个队列(其中可以推送项目),则应返回“需要处理的项目”而不是“百分比”。 - Jeroen van Langen
@Jordy van Eijk,您的问题已经有3个答案了,请回复这些答案并解释它们为什么不适合或选择一个被接受的答案。 :) - Skintkingle
2个回答

3

引擎可以维护每个进程的“最后完成度”私有列表,很可能是通过字典实现。

如果我们将您的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 });
}

您将从您的引擎报告所有任务的总完整度。

这存在一些明显的设计缺陷,但您可以理解它。如果处理器不是从构造函数中加载的,则可以将其扩展为可变数量的处理器等,但这应该会给您带来所需的输出。


谢谢你的回答。这对我很有帮助。虽然我需要做一些调整,但这是解决我的问题的好方法。 - Jordy van Eijk

0
我建议让每个处理器记录其已完成的项目数和剩余的项目数。
这样引擎就会在每个项目完成时接收更新,以及在将项目添加到处理器时接收更新。
如Skintkingle的答案所述,您可以在引擎内存储每个处理器最后收到的更新。
然后,您可以让引擎决定如何最好地传达这些信息。 简单的总完成/总剩余就可以很好地工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接