UWP异步方法仅调用MessageDialog时生效的问题咨询
嘿,Laura!我一眼就看出问题所在啦,咱们一步步来解决这个缩略图延迟显示的问题:
问题根源分析
你现在的代码有两个核心问题导致缩略图要等对话框关闭才显示:
- 调用时机错误:你在解压所有文件之前就调用了
thumbnailCallback,这时候thumbnail.jpg还没被解压到目标文件夹,Uri指向的文件根本不存在,自然加载不出来;而MessageDialog阻塞了线程,等你关闭对话框时,后续的解压操作刚好完成,文件才存在,图片才显示。 - MessageDialog阻塞UI渲染:
ShowAsync()会暂停当前UI线程的更新流程,哪怕你创建了UI元素,也得等对话框关闭后才会触发渲染。
另外还有两个小问题:
- 直接用本地路径拼接Uri在UWP里可能遇到权限限制,正确的做法是通过
StorageFile来加载图片。 - 你创建了
Canvas但没有把它添加到页面的可视化树里(比如页面的Grid/StackPanel容器),就算创建了元素也不会显示在界面上。
解决方案步骤
1. 调整解压顺序,先解压缩略图
修改UnZipFileHelper,先找到thumbnail.jpg并优先解压,再调用回调显示缩略图,这样文件已经存在,图片能正常加载:
private static async Task UnZipFileHelper(StorageFile zipFile, StorageFolder destinationFolder, Action<ZipArchiveEntry, StorageFolder> thumbnailCallback, Action<ZipArchiveEntry> completeCallback) { if (zipFile == null || destinationFolder == null || !Path.GetExtension(zipFile.Name).Equals(".zip", StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException("Invalid argument..."); } Stream zipMemoryStream = await zipFile.OpenStreamForReadAsync(); using (ZipArchive zipArchive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read)) { // 优先找到并解压thumbnail.jpg ZipArchiveEntry thumbnailEntry = zipArchive.GetEntry("thumbnail.jpg"); if (thumbnailEntry != null) { // 先解压缩略图文件 await UnzipZipArchiveEntryAsync(thumbnailEntry, thumbnailEntry.FullName, destinationFolder); // 现在文件已经存在,调用回调显示 thumbnailCallback(thumbnailEntry, destinationFolder); } // 再解压其他文件 foreach (ZipArchiveEntry entry in zipArchive.Entries) { // 跳过已经解压的缩略图 if (entry.FullName.Equals("thumbnail.jpg", StringComparison.OrdinalIgnoreCase)) continue; await UnzipZipArchiveEntryAsync(entry, entry.FullName, destinationFolder); // 触发单个文件完成的回调 completeCallback?.Invoke(entry); } } }
2. 重写thumbnailCallback,移除MessageDialog并正确加载图片
移除阻塞的对话框,用StorageFile加载图片,并且把创建的Canvas添加到页面的可视化容器里(假设你的页面有个名为MainContentGrid的Grid容器):
public async void thumbnailCallback(ZipArchiveEntry thumbnailEntry, StorageFolder destinationFolder) { // 确保在UI线程执行操作 await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => { // 获取已解压的缩略图文件 StorageFile thumbnailFile = await destinationFolder.GetFileAsync(thumbnailEntry.FullName); // 创建Canvas和控件 Canvas canvas = new Canvas { Width = 200, Height = 125 }; ProgressRing progressRing = new ProgressRing { Name = thumbnailEntry.FullName, IsActive = true, Height = 50, Width = 50 }; Canvas.SetTop(progressRing, 35); Canvas.SetLeft(progressRing, 75); Canvas.SetZIndex(progressRing, 2); Image thumbImage = new Image { Name = thumbnailEntry.FullName, Width = 200, Height = 125, Opacity = 0.2 }; // 用StorageFile加载图片,避免权限问题 BitmapImage bitmapImage = new BitmapImage(); using (IRandomAccessStream stream = await thumbnailFile.OpenAsync(FileAccessMode.Read)) { await bitmapImage.SetSourceAsync(stream); } thumbImage.Source = bitmapImage; // 添加控件到Canvas canvas.Children.Add(thumbImage); canvas.Children.Add(progressRing); // 将Canvas添加到页面的可视化容器(替换成你实际的容器名) MainContentGrid.Children.Add(canvas); }); }
3. 上传完成后关闭进度环
在completeCallback里,根据文件名找到对应的ProgressRing并关闭它:
public void OnFileUnzipComplete(ZipArchiveEntry entry) { // 如果是缩略图所在的zip包完成,关闭进度环 if (entry.FullName.Equals("thumbnail.jpg", StringComparison.OrdinalIgnoreCase)) { Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { ProgressRing progressRing = MainContentGrid.FindName(entry.FullName) as ProgressRing; if (progressRing != null) { progressRing.IsActive = false; // 同时调整图片透明度为1 Image thumbImage = MainContentGrid.FindName(entry.FullName) as Image; if (thumbImage != null) { thumbImage.Opacity = 1; } } }); } }
4. 调用UnZipFileAsync时传入完成回调
修改OnFileDrop里的调用代码,传入完成回调:
await UnZipFileAsync(appFile, unzipFolder, thumbnailCallback, OnFileUnzipComplete);
额外提示
- 记得在页面的XAML里定义一个容器,比如:
<Grid x:Name="MainContentGrid" AllowDrop="True" DragOver="OnDragOver" Drop="OnFileDrop"> <!-- 其他控件 --> </Grid>
- 处理图片加载失败的情况,可以给Image添加
ImageFailed事件,显示默认占位图。
这样修改后,缩略图会在解压完成后立刻显示,进度环也会在整个上传(解压)完成后自动关闭,再也不需要依赖MessageDialog啦!
内容的提问来源于stack exchange,提问作者Laura M
相关产品推荐
相关产品推荐

