【问题标题】:Can't read all files properly from StorageFile in Windows 8 metro application无法从 Windows 8 Metro 应用程序中的 StorageFile 正确读取所有文件
【发布时间】:2012-03-06 22:14:28
【问题描述】:

我正在 Windows 8 Metro 应用程序中开发一个简单的应用程序,我正在尝试从 PicturesLibrary 中检索文件,我输入的代码如下:

public async void Initialize()
{
    IReadOnlyList<StorageFile> storageFiles = await KnownFolders.PicturesLibrary.GetFilesAsync();              
    foreach (var storageFile in storageFiles)
    {   
        BitmapImage bitmapImage = new BitmapImage();
        FileRandomAccessStream stream = (FileRandomAccessStream)await storageFile.OpenAsync(FileAccessMode.Read);
        bitmapImage.SetSource(stream);
        Image image = new Image();
        image.Source = bitmapImage;
        Images.Add(image);
    }
}

然后我使用它们的 ImageSource 显示这些图像。 我遇到的问题是,有时它会显示所有内容,有时会显示一个 或两个,有时它不显示任何图像,我不明白这是因为等待方法 GetFileAsync() 还是我可能缺少的其他东西。

提前致谢:)

【问题讨论】:

  • 为什么不试试 NON-async 方法,看看你是否始终如一地获取所有文件?
  • @jberger - 没有这样的 API 可用,Metro 有很多只异步的,就像 Silverlight 以前那样。
  • 我还不熟悉 async/await,但似乎 StorageFolder.GetFilesAsync() 返回了一个 IAsyncOperation&lt;IReadOnlyList&gt; ,而 IAsyncOperation&lt;IReadOnlyList&gt; 又是一个 Completed 事件..
  • 到底发生了什么?图片在storageFiles,但没有显示?还是他们在storageFiles 中丢失了?另外,如果没有必要,您不应该编写 async void 方法。
  • 您的内存使用情况如何?看起来您正在将所有图像读入内存。

标签: c# wpf windows-runtime async-await


【解决方案1】:

我猜这只是时间问题,但在 foreach 中设置断点或跟踪点肯定会说明问题。

尝试将其更改为返回任务,然后在你的调用者中等待它

【讨论】:

  • 谢谢@James,是的,我认为这是一个时间问题,正如你所说,我在 foreach 循环中尝试了一些断点,效果更好,但由于我不太熟悉异步操作,所以我不非常确定如何实施您的解决方案,如果您给我一些链接,我将非常感谢,再次感谢。
  • 只需在方法声明中将 void 更改为 Task,然后让调用者 await 或 .Wait() 取决于调用者是否也可以/应该是异步的
  • 非常感谢@James,我解决了,现在完美运行,谢谢谢谢:)
  • 我的猜测是使用图像的视图正在获取图像的内容,而此函数仍在将位图放入图像中。没关系,如果 Images 是 ObservableCollection,则视图可以在添加图像时更新。
【解决方案2】:

我认为你的问题将是这一行。

FileRandomAccessStream stream = (FileRandomAccessStream)await storageFile.OpenAsync(FileAccessMode.Read);

在循环中等待可能会给您带来一些奇怪的范围问题。
我会尝试的第一件事是切换这个循环的前两行。

FileRandomAccessStream stream = (FileRandomAccessStream)await storageFile.OpenAsync(FileAccessMode.Read);
BitmapImage bitmapImage = new BitmapImage();

可能是 bitmapImage 引用被重新指向您。如果这没有帮助,您可能需要查看 .ContinueWith 方法。

storageFile.OpenAsync(FileAccessMode.Read).ContinueWith(task => {
  FileRandomAccessStream stream = (FileRandomAccessStream)task.Result;
  BitmapImage bitmapImage = new BitmapImage();
  bitmapImage.SetSource(stream);
  Image image = new Image();
  image.Source = bitmapImage;
  Images.Add(image);
});

【讨论】:

  • 嗨@Chris,我尝试切换这两行但没有成功,即使没有定义 .ContinueWith() 方法。感谢您的帮助。
【解决方案3】:

好的,感谢你们,我找到了解决方案,我不得不重新排列代码,

public async Task Initialize()
        {   
            IReadOnlyList<StorageFile> storageFiles = await KnownFolders.PicturesLibrary.GetFilesAsync();              
            foreach (var storageFile in storageFiles)
            {
                var image = new Image();
                image.Source = await GetBitmapImageAsync(storageFile);
                Images.Add(image);
            }
        }

        public async Task<BitmapImage> GetBitmapImageAsync(StorageFile storageFile)
        {
            BitmapImage bitmapImage = new BitmapImage();
            IAsyncOperation<IRandomAccessStream> operation = storageFile.OpenAsync(FileAccessMode.Read);
            IRandomAccessStream stream = await operation;
            bitmapImage.SetSource(stream);
            return bitmapImage;
        }

然后调用 OnNavigateTo 事件中的所有内容,因为构造函数不能是异步的

 protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            _imageList = new ImagesList();
            await _imageList.Initialize();
            foreach (var image in _imageList.Images)
            {
                Image img = new Image() { Source = image.Source };
                img.Width = img.Height = 200;
                img.Margin = new Thickness(20, 0, 20, 0);
                img.ImageFailed += image_ImageFailed;
                img.PointerEntered += img_PointerEntered;
                img.PointerExited += img_PointerExited;
                sp_MainStackPanel.Children.Add(img);
            }
        }

再次感谢大家!

【讨论】:

  • FWIW,您可以将 'await _imageList.Initialize()' 更改为 '_imageList.Initialize().Wait()' 然后代码可以放入 ctor 中(因为它会运行在那个时候同步而不是重写)。如果您正在使用异步 API 并且不希望调用者是异步的,那么只需与返回的任务正常交互(例如,调用 Wait())就可以了。当您希望调用者也异步时,您只需要“等待”:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多