How to display images from Picture Directory ?

2019-07-07 02:24发布

I want to display pictures in the Pictures library. I get pictures and bind data.

StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
IReadOnlyList<StorageFile> myPictures = await picturesFolder.GetFilesAsync();
var mydata = from file in myPictures select new { Subtitle = "subtitle", Title = "title", Image = this.getImage(file.Path) };

this.DefaultViewModel["Items"] = mydata;

This is getImage() for set BitmapImage.

private async Task<BitmapImage> getImage(string finename)
{
    StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
    StorageFile file = await picturesFolder.GetFileAsync(fileName);
    var stream = await file.OpenReadAsync();

    var bitmap = new BitmapImage();
    bitmap.SetSource(stream);

    return bitmap;
 }

But pictures are not displayed.I think this is because of async function, but I don't know the solution. Could you help me ?

2条回答
Ridiculous、
2楼-- · 2019-07-07 02:42

I'm not sure how do you use the data that set to DefaultViewModel, but yeah, it looks like the async method is your problem.

What you need to do is to somehow await each call to getImage(). One way to do this is to use async lambda in your select. But to do that, you need to use the method syntax.

When you do that, you will have IEnumerable<Task<a>> (where a is your anonymous type), but you need just IEnumerable<a>. To get that, use Task.WhenAll() (which will return Task<a[]>) and then await its result:

var tasks = myPictures.Select(
    async file => new { Subtitle = "subtitle", Title = "title", Image = await getImage(file.Path) });
var data = await Task.WhenAll(tasks);

This will execute all getImage()s at once, which may not be the most efficient solution. If you don't want that, you would need different solution.

查看更多
三岁会撩人
3楼-- · 2019-07-07 03:05

svick's solution seems like should work, but as he/she said - it might not be the most efficient solution. A better solution for a folder with unknown number of files is to use data virtualization with FileInformationFactory.GetVirtualizedFilesVector(). That works best with a converter.

Something I have used:

Getting a virtualized file list and binding to a ListView

private async void GetPicturesFromGalleryFolder()
{
    var queryOptions = new QueryOptions();
    queryOptions.FolderDepth = FolderDepth.Shallow;
    queryOptions.IndexerOption = IndexerOption.UseIndexerWhenAvailable;
    queryOptions.SortOrder.Clear();

    var sortEntry = new SortEntry {PropertyName = "System.DateModified", AscendingOrder = false};
    queryOptions.SortOrder.Add(sortEntry);
    queryOptions.FileTypeFilter.Add(".png");

    var fileQuery = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);
    var fileInformationFactory =
        new FileInformationFactory(
            fileQuery,
            ThumbnailMode.PicturesView,
            0,
            ThumbnailOptions.None,
            true);

    MyListView.ItemsSource = fileInformationFactory.GetVirtualizedFilesVector();
}

XAML

<ListView.ItemTemplate>
    <DataTemplate>
        <Image
            Source="{Binding Converter={StaticResource converters:IStorageItemInformationToBitmapImageConverter}"/>
    </DataTemplate>
</ListView.ItemTemplate>

IStorageItemInformationToBitmapImageConverter

public class IStorageItemInformationToBitmapImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        var fileInfo = value as FileInformation;

        if (fileInfo != null)
        {
            var bi = new BitmapImage();

            // The file is being opened asynchronously but we return the BitmapImage immediately.
            SetSourceAsync(bi, fileInfo);
            return bi;

        }

        return null;
    }

    private async void SetSourceAsync(BitmapImage bi, FileInformation fi)
    {
        try
        {
            using (var stream = await fi.OpenReadAsync())
            {
                await bi.SetSourceAsync(stream);
            }
        }
        catch
        {
            // ignore failure
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return null;
    }
}
查看更多
登录 后发表回答