Может, сделать как-то так?
int working_tasks = 0;
ManualResetEventSlim pre = new ManualResetEventSlim(false);
// здесь запуск тасков
// в каждом таске (в начале) ставим working_tasks = Interlocked.Increment(working_tasks);
// в конце - if(Interlocked.Read(working_tasks) == 0) { pre.Set(); }
pre.Wait();
// здесь то, что должно выполняться после выполнения всех тасков
Таким образом, в начале выполнения таска увеличиваем некую переменную на 1, в конце - уменьшаем на 1. Если все таски выполнены (переменная равна 0) - ставим флаг резет-ивента - и начинает выполняться код после pre.Wait().
Не уверен в правильности (писал по памяти), но идея вроде рабочая. Поправьте, если я не прав.