Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 任务上的异步/等待进度事件<&燃气轮机;对象_C#_Async Await - Fatal编程技术网

C# 任务上的异步/等待进度事件<&燃气轮机;对象

C# 任务上的异步/等待进度事件<&燃气轮机;对象,c#,async-await,C#,Async Await,我对C#5新的async/wait关键字完全陌生,我对实现进度事件的最佳方式感兴趣 现在,我更希望进度事件发生在任务本身上。我知道我可以将事件放在包含异步方法的类中,并在事件处理程序中传递某种状态对象,但对我来说,这更像是一种解决方法,而不是解决方案。我可能还希望不同的任务在不同的对象中触发事件处理程序,这听起来很混乱 我有没有办法做类似的事情 var task = scanner.PerformScanAsync(); task.ProgressUpdate += scanner_Progre

我对C#5新的
async
/
wait
关键字完全陌生,我对实现进度事件的最佳方式感兴趣

现在,我更希望
进度
事件发生在
任务
本身上。我知道我可以将事件放在包含异步方法的类中,并在事件处理程序中传递某种状态对象,但对我来说,这更像是一种解决方法,而不是解决方案。我可能还希望不同的任务在不同的对象中触发事件处理程序,这听起来很混乱

我有没有办法做类似的事情

var task = scanner.PerformScanAsync();
task.ProgressUpdate += scanner_ProgressUpdate;
return await task;

简单地说,
任务
不支持进度。然而,已经有一种传统的方法来实现这一点,即使用接口。基本上,建议重载异步方法(在有意义的情况下)以允许客户端在
iproges
实现中传递。然后,您的异步方法将通过它报告进度


Windows运行时(WinRT)API在和类型中确实内置了进度指示器。。。因此,如果您实际上是为WinRT编写的,那么这些都是值得研究的,但也请阅读下面的注释。

文档中描述了推荐的方法,它为每个异步方法提供了自己的
IProgress

公共异步任务PerformCanAsync(IProgress进程)
{
...
如果(进度!=null)
进度报告(新的MyScanProgress(…);
}
用法:

var progress = new Progress<MyScanProgress>();
progress.ProgressChanged += ...
PerformScanAsync(progress);
var progress=newprogress();
progress.ProgressChanged+=。。。
PerformCanasync(进度);
注:

  • 按照惯例,如果调用者不需要进度报告,
    progress
    参数可能是
    null
    ,因此一定要在
    async
    方法中检查这一点
  • 进度报告本身是异步的,因此每次调用时都应该创建一个新的参数实例(更好的是,只需为事件args使用不可变类型)。对于对
    Progress
    的多个调用,不应变异然后重新使用同一arguments对象
  • Progress
    类型将捕获构建时的当前上下文(例如,UI上下文),并在该上下文中引发其
    ProgressChanged
    事件。因此,在调用
    Report
    之前,您不必担心封送回UI线程

  • 我不得不从几篇文章中拼凑出这个答案,因为我正试图找出如何使这项工作适用于不那么琐碎的代码(即事件通知更改)

    让我们假设您有一个同步项目处理器,它将宣布即将开始工作的项目编号。在我的例子中,我只是要操作流程按钮的内容,但是你可以很容易地更新进度条等

    private async void BtnProcess_Click(object sender, RoutedEventArgs e)
    {       
        BtnProcess.IsEnabled = false; //prevent successive clicks
        var p = new Progress<int>();
        p.ProgressChanged += (senderOfProgressChanged, nextItem) => 
                        { BtnProcess.Content = "Processing page " + nextItem; };
    
        var result = await Task.Run(() =>
        {
            var processor = new SynchronousProcessor();
    
            processor.ItemProcessed += (senderOfItemProcessed , e1) => 
                                    ((IProgress<int>) p).Report(e1.NextItem);
    
            var done = processor.WorkItWorkItRealGood();
    
            return done ;
        });
    
        BtnProcess.IsEnabled = true;
        BtnProcess.Content = "Process";
    }
    
    private async void BtnProcess\u单击(对象发送方,路由目标)
    {       
    BtnProcess.IsEnabled=false;//防止连续单击
    var p=新进展();
    p、 ProgressChanged+=(SenderOffProgressChanged,nextItem)=>
    {BtnProcess.Content=“处理页面”+nextItem;};
    var result=等待任务。运行(()=>
    {
    var processor=新的SynchronousProcessor();
    processor.ItemProcessed+=(senderOfItemProcessed,e1)=>
    ((IProgress)p.)报告(e1.NextItem);
    var done=processor.worktworkitrealgood();
    已完成的返回;
    });
    BtnProcess.IsEnabled=true;
    BtnProcess.Content=“流程”;
    }
    

    这方面的关键部分是关闭
    Progress
    订阅中的
    ItemProcessed
    变量。这允许一切
    正常工作™

    当使用任务时。运行lambda我使用了其中的调用操作来更新ProgressBar控件。这可能不是最好的方法,但它在紧要关头起作用,而不必进行任何重组

       Invoke(new Action(() =>
    
                   {
                       LogProgress();
                   }));
    
    这就意味着

            private void LogProgress()
            {       
              progressBar1.Value = Convert.ToInt32((100 * (1.0 * LinesRead / TotalLinesToRead)));
            }
    

    对于WinRT,使用
    IProgress
    (遵循C#约定)编写一个正常的
    async
    方法要容易得多然后使用
    AsyncInfo.Run
    将其包装成
    IAsyncOperationWithProgress
    /
    iasyncationwithprogress
    ,而不是直接实现这些接口。@StephenCleary:这取决于您考虑的是调用方还是实现。如果您试图公开功能供其他人调用,我认为WinRT“本机”类型更合适。很明显,两者之间有各种转换器。在C中遵循C约定,在边界处使用包装器(
    AsTask
    /
    AsyncInfo
    )更容易。因此,用C实现的WinRT组件将返回WinRT接口类型,但将使用
    async
    封装在
    AsyncInfo
    @StephenCleary中的常规
    async
    实现它:很公平,我相信你的话:)只是为了让我理解,也许是为了将来帮助其他人。。。你对第二点的推理。如果在Report方法完成之前对传递给Progress.Report()的可变对象进行了更改,则会导致未报告原始值?几乎是这样。我的意思是,当
    报告
    方法完成(并返回)时,实际的报告尚未发生。如果您的
    T
    是可变的,并且您在将其传递到
    Report
    后对其进行了更改,那么您就有了竞争条件。实际报告可能会看到旧值、新值或混合值(即,某些字段的旧值和其他字段的新值)。是的,现在这更有意义了,谢谢。我读了一些你的博客,其中你提到了比赛条件,但直到我读到这个问题后才发现。Thanks那么ProgressChanged委托是否可以按顺序获得Report()'d?根据我的理解,即使传递的对象是不可变的,如果我用
            private void LogProgress()
            {       
              progressBar1.Value = Convert.ToInt32((100 * (1.0 * LinesRead / TotalLinesToRead)));
            }