如何在C#中等待异步任务完成? [重复]

问题描述 投票:-1回答:1

这个问题在这里已有答案:

我正在使用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方法

c# async-await
1个回答
8
投票

问题在于这是对async void的滥用,这使你无法等待它。当你开始时,一个好的规则是,如果你输入单词async void stop ...从你的计算机退后一步,告诉你自己可能有更好的方法......它们应该主要用于事件处理程序。

基本上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方法调用它并等待它,因为它仍然返回一个任务并标记为async

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); 

关于这段代码还有更多的问题,但我认为它们可能属于另一个问题

© www.soinside.com 2019 - 2024. All rights reserved.