How to display images from the Picture Directory?
I want to display images in the Pictures library. I receive photos and link 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 the getImage () method for setting the 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 the pictures are not displayed. I think it is because of the async function, but I don't know the solution. could you help me?
source to share
I'm not sure how you are using the data that is set to DefaultViewModel
, but yes, it looks like the method async
is your problem.
What you need to do is await
each challenge one way or another getImage()
. One way to do this is to use async
lambda in select
. But you need to use method syntax for this.
When you do this, you have IEnumerable<Task<a>>
(where a
is your anonymous type), but you only need IEnumerable<a>
. To get this 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 do everything at getImage()
once, which may not be the most efficient solution. If you don't want this, you will need a different solution.
source to share
Svick's solution seems to work, but as he said it might not be the most efficient solution. The best solution for a folder with an unknown number of files is to use data virtualization with FileInformationFactory.GetVirtualizedFilesVector()
. This works best with a converter.
Something I used:
Getting list of virtualized files and binding to 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;
}
}
source to share