c# - 如何在 C# 中等待异步任务完成?
问题描述
我正在使用 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 方法
解决方案
这里的问题是滥用,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 Task
当一个异常从or方法中抛出时async 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);
这段代码还有很多不确定的地方,但是我认为它们可能应该属于另一个问题
推荐阅读
- javascript - 如何将 react-native expo 应用程序导出到旧版本的 android 操作系统?
- go - 尝试连接到启用 TLS1.2 的 Oracle DB 时出现“ORA-28759:无法打开文件”
- php - 如何在共享主机上部署 laravel websockets?
- laravel - 警告:无法打开目录“public/img/dir-foe”:使用 Laravel 拒绝权限
- haskell - Haskell 类型推断
- python - 在 PyTorch 的 GPU 上使用 DataLoader 训练 CNN 模型
- c# - 自行安装 AspNetCoreModuleV2,或确保已安装
- prestashop-1.7 - Prestashop 外部支付模块
- wordpress - 带有子项列表(类别或页面)的自定义面包屑
- python - 在 POST 方法上呈现另一个视图