如何在C#中等待异步任务完成?

时间:2019-04-12 05:14:32

标签: c# async-await

我正在使用uwp应用程序中的RenderTargetBitmap将UIelement转换为流。但是我不知道如何让线程等到流的转换。我尝试使用建议,但是找不到合适的解决方案。非常感谢您的帮助。

   {
      for (int count = 0; count <= Textpage.Children.Count; count++)
      {
         if (Textpage.Children[count] is Viewbox)
         {
            CustomView customView = (Textpage.Children[count] as Viewbox).Child as CustomView;
            UIElement frameworkElement = customView as UIElement;
            (Textpage.Children[count] as Viewbox).Child = null;
            var element = (PdfDocumentPanel.Children[count] as Border).Child as Canvas;
            Textpage.Children.Remove((Textpage.Children[count] as Viewbox));

            SaveCustomAnnotation(frameworkElement, pageIndex, documentToBeSaved);

         }
      }

   }

   Stream savedStream = new MemoryStream();
}

internal async void SaveCustomAnnotation(UIElement element, int pageIndex, PdfLoadedDocument loadedDocument)
{

   Type pageChild = null;

   IRandomAccessStream randomStream;

   randomStream = await Task.Run(() => ConvertToImage(element));

}

public async Task<IRandomAccessStream> ConvertToImage(UIElement element)
{

   InMemoryRandomAccessStream randomAccessStream = null;
   IBuffer pixelBuffer = null;
   RenderTargetBitmap bitmap = new RenderTargetBitmap();


   await bitmap.RenderAsync(element);

   pixelBuffer = await bitmap.GetPixelsAsync();

   var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
   using (randomAccessStream = new InMemoryRandomAccessStream())
   {
      var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, randomAccessStream);
      encoder.SetPixelData(
      BitmapPixelFormat.Bgra8,
      BitmapAlphaMode.Ignore,
      (uint)bitmap.PixelWidth,
      (uint)bitmap.PixelHeight,
      logicalDpi,
      logicalDpi,
      pixelBuffer.ToArray());
      await encoder.FlushAsync();

   }
   return randomAccessStream;
}

我希望在完成初始化新的内存流之前完全完成SaveCustomannotation方法

1 个答案:

答案 0 :(得分:8)

问题出在这里是async void滥用,这阻止了您等待。入门时的一个好规则是,如果您输入单词async void停止...从计算机上退后一步,然后告诉自己,可能还有更好的方法...应该主要使用它们用于事件处理程序。

基本上SaveCustomAnnotation应该返回Task

internal async Task SaveCustomAnnotation(UIElement element, int pageIndex, PdfLoadedDocument loadedDocument)

然后您需要await

await SaveCustomAnnotation(frameworkElement, pageIndex, documentToBeSaved);

这样,它的调用方法也应该是async Task(一直到调用链的整个末端),只有这样,它们的调用方法才应该是async void,并且必须是事件处理程序。

最后一个提示

Async void方法具有不同的错误处理语义。如果从async Taskasync Task<T>方法抛出异常,则捕获该异常并将其放置在Task上。使用async void方法时,没有Task对象(它们是不可观察的),因此从async void方法抛出的任何异常都将直接在启动时处于活动状态的SynchronizationContext上引发。

简而言之,总是使用此类方法捕获并处理来自其中的异常


(正确的说)Jonathon Chase一样。

如果这是全部操作,您可能应该只从main方法调用它并等待它,因为它无论如何都会返回任务并标记为

internal async void SaveCustomAnnotation(UIElement element, int pageIndex, PdfLoadedDocument loadedDocument)
{
   Type pageChild = null;
   IRandomAccessStream randomStream;
   randomStream = await Task.Run(() => ConvertToImage(element));
}

您可以删除整个方法,而只需替换

await SaveCustomAnnotation(frameworkElement, pageIndex, documentToBeSaved);

var readstream = await ConvertToImage(frameworkElement); 

有关此代码的还有 iffy ,但是我认为它们应该属于另一个问题