C# 任务在通知进度之前完成。为什么以及如何修复?

C# 任务在通知进度之前完成。为什么以及如何修复?,c#,wpf,asynchronous,task,C#,Wpf,Asynchronous,Task,因此,我尝试使用IProgress使用任务进度通知。以下是我的工作: 创建一个Progress并将处理程序附加到其ProgressChanged事件 在事件处理程序中,我更新UI特定属性以显示进度 运行循环并创建任务对象以完成工作单元。每个任务都使用Progress对象来报告进度(这将依次调用ProgressChanged并更新UI) 使用Task.WaitAll()阻止,直到所有任务完成。在结尾显示完成消息 代码如下所示: IProgress<Tuple<DataRow, MyVM

因此,我尝试使用
IProgress
使用任务进度通知。以下是我的工作:

  • 创建一个
    Progress
    并将处理程序附加到其
    ProgressChanged
    事件
  • 在事件处理程序中,我更新UI特定属性以显示进度
  • 运行循环并创建
    任务
    对象以完成工作单元。每个任务都使用
    Progress
    对象来报告进度(这将依次调用
    ProgressChanged
    并更新UI)
  • 使用
    Task.WaitAll()
    阻止,直到所有任务完成。在结尾显示完成消息
  • 代码如下所示:

    IProgress<Tuple<DataRow, MyVM>> BakeProgress;
    BakeProgress = new Progress<Tuple<DataRow, MyVM>>();
    
    ((Progress<Tuple<DataRow, MyVM>>)BakeProgress).ProgressChanged += (sender, args) =>
    {
      _BakeProgress += 100.0 / AllDataRows.Length;
      RaisePropertyChanged(NameOf(BakeProgress));
    };
    
    var BakeTasks = new List<Task>();
    foreach (var dr in AllDataRows) {
    
      BakeTasks.Add(Task.Run(() =>
      {
        var Baked = MyBakingFunc();
    
        BakeProgress.Report(new Tuple<DataRow, MyVM>(dr, Baked));
    
        return Baked;
      }));
    }
    
    Task.WaitAll(BakeTasks.ToArray());      //Shouldn't this wait
    
    MessageBox.Show("Baking Completed");
    
    IProgress-BakeProgress;
    BakeProgress=新进展();
    ((进度)BakeProgress.ProgressChanged+=(发送方,参数)=>
    {
    _BakeProgress+=100.0/AllDataRows.Length;
    RaisePropertyChanged(BakeProgress)名称);
    };
    var BakeTasks=新列表();
    foreach(所有数据行中的var dr){
    BakeTasks.Add(Task.Run)(()=>
    {
    var Baked=MyBakingFunc();
    BakeProgress.Report(新元组(dr,Baked));
    返烤;
    }));
    }
    Task.WaitAll(BakeTasks.ToArray())//这不是应该等一下吗
    MessageBox.Show(“烘焙完成”);
    
    令我惊讶的是,此代码在命中
    ProgressChanged
    事件处理程序之前,甚至只命中了
    MessageBox
    line。我做错了什么

    注意:对于每个任务实例,它确实会命中
    ProgressChanged
    事件处理程序一次,但只有在命中完成行之后才会命中


    注意:啊,我确实读过,但由于这是WPF,我们确实有一个同步上下文,在其中创建了
    进度
    对象。

    提示:您不需要
    任务。运行
    ,您应该使用
    等待任务。当所有
    而不是
    任务。WaitAll
    时,请使用
    camelCase
    作为局部变量和参数,不是
    PascalCase
    @Dai:谢谢。为什么我不需要
    任务。运行
    ?你是说我不应该使用多线程吗?正如你所看到的,在你的例子中,进程处理程序将在UI线程上运行。但您的UI在等待所有任务完成时被阻止。因此,只有在所有任务完成(并显示消息框)后,UI线程才可用于运行进度处理程序。@Dai:我对参数使用camelCase,但对局部变量使用PascalCase。不确定我是什么时候开始采用这种风格的,但它有时确实对我有所帮助。