4

我想订阅一个在引发所有多个其他事件时将引发的事件。

假设我有多个任务AB完成的。

第一个任务(A)的数量每次都可能不同,所以目前我设置了一个任务数的计数器A,订阅 N 个事件,并在任务完成的事件处理程序中减少计数器,当它为零时,我做任务 B。

有没有比使用计数器更好的方法来组合这些事件?

4

2 回答 2

1

如果我正确理解了这个问题,则在启动 A 任务时增加一个计数器,当每个任务完成时,减少事件处理程序中的计数器。同样在事件处理程序中,您检查(在递减计数器之后)计数器是否为零。如果是这样,您执行任务 B。

我建议您查看Tasks又名“任务并行库 (TPL)”),它允许您执行以下操作:

Task.WhenAll( new Task[] {
    Task.Run(()=> { //... do work A1... },
    Task.Run(()=> { //... do work A2... },
    Task.Run(()=> { //... do work A3... }})
    .ContinueWith(()=> {//... do work B... });

更新:根据您在下面的评论中提到的 WPF 动画,Task.Run可能不适合这里。如果我没记错的话,你会得到一个Completed事件,并且没有办法在代码中同步运行动画(如“...做 A1...”)。

但是,Task.Run您可以通过扩展方法从Completeda 的事件中创建它们,而不是通过创建任务,例如:Storyboard

public static Task<Storyboard> BeginAsync(this Storyboard sb)
{
   var tcs = new TaskCompletionSource<Storyboard>();
   sb.Completed += (s, a) => tcs.TrySetResult(sb);
   sb.Begin();
   return tcs.Task;
}

请注意,此方法创建一个任务,该任务在情节提要的Completed事件处理程序中完成,并在返回任务之前开始情节提要动画。另请注意,您可以为其他类型和事件编写类似的扩展方法。

您可以使用这种方法,例如:

var sb1 = (Storyboard)mainWindow.FindResource("Storyboard1");
var sb2 = (Storyboard)mainWindow.FindResource("Storyboard2");
var sb3 = (Storyboard)mainWindow.FindResource("Storyboard3");

Task.WhenAll( new Task[] {
    sb1.BeginAsync(),
    sb2.BeginAsync(),
    sb3.BeginAsync() })
    .ContinueWith(() => MessageBox.Show("All done!"),
        TaskScheduler.FromCurrentSynchronizationContext());

TaskScheduler.FromCurrentSynchronizationContext()基本上安排继续任务在 UI 线程上运行(如果您将访问 UI 元素,则需要这样做)。

于 2013-08-26T08:02:27.163 回答
0

我将为每个事件创建一个标识符(例如,基于枚举),然后将您希望调用的所有事件添加到列表中。每当执行事件时,我都会将其从列表中删除。

在每种情况下,您调用一个方法,该方法仅在列表为空时才真正执行任何工作。

于 2013-08-26T08:19:42.040 回答