C#在引发所有事件(或组合事件)后做一些工作

本文关键字:事件 工作 组合 | 更新日期: 2023-09-27 18:28:57

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

假设我首先要做多个任务(A)(例如为多个独立视图设置动画),我也可以订阅任务完成的事件,并且我想在所有这些事件完成后做一些其他工作(B)。

第一个任务的数量(A)每次都可能不同,所以现在我将计数器设置为任务数量A,订阅N个事件,在任务完成的事件处理程序中,我递减计数器,当计数器为零时,我执行任务B。

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

C#在引发所有事件(或组合事件)后做一些工作

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

我建议你看看任务(,又名"任务并行库(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…")

但是,您可以通过以下扩展方法从StoryboardCompleted事件创建任务,而不是通过Task.Run创建任务:

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元素,这是必需的)。

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

在每种情况下,您都会调用一个方法,该方法只有在列表为空时才会实际执行任何工作。

相关文章: