I have a GridView with elements containing a TextBlock and an Image. The TextBlock always populates fine, but the Image, once in a while, does not get loaded for one or two items. If I refresh the data source, the image correctly displays. I think the issue is with the timing (all data fetching is done asynchronously).
Here is the code that fetches the images from disk. All images are 140×140 pixels and are PNG files.
public async Task<List<BitmapImage>> getPhotos()
{
photos.Clear(); //clears list of photos
IReadOnlyList<IStorageFile> files = (IReadOnlyList<IStorageFile>)await folderHierarchy.Last().GetFilesAsync(); //reads in all files from current working directory
foreach (StorageFile currentFile in files) //for each file in that directory
{
if (currentFile.Name.EndsWith(".png")) //only handle png files
{
photos.Add(await getBitmapImageAsync(currentFile)); //actually read in image from separate async method (bellow)
}
}
return photos;
}
public async Task<BitmapImage> getBitmapImageAsync(StorageFile storageFile)
{
BitmapImage image = new BitmapImage();
FileRandomAccessStream stream = (FileRandomAccessStream) await storageFile.OpenAsync(FileAccessMode.Read);
image.SetSource(stream);
return image;
}
I run this method using: List tilePicturesArray = await dataFetcherClass.getPhotos();
The original photos List does not contain all of the photos. Something wrong is happening in that first block of code (above).
The next step is when I populate the Image and TextBox via in my List (GridViewCell is a class that I made to bind data in my GridView) The list of GridViewCell objects is what is binded to my GridView. I don’t believe that this is the issue.
for (int x = 0; x < tileTitlesArray.Count; x++) //this IS running inside of an async method
{
GridViewCell singleCell = new GridViewCell();
singleCell.tileName = tileTitlesArray.ElementAt(x);
singleCell.tileImage = tilePicturesArray.ElementAt(x);
tileCells.Add(singleCell); //tileCells is the datasource for gridview
}
What do you think would be causing the issue? I added a little refresh button which basically reruns the above loop (to repopulate the gridview datasource and tiles) but does not refetch the tilePicturesArray, so the binding is done using the same original List of BitmapImages (and the same tiles are still missing pictures)
About 20 min after posting this, someone on the msdn forums answered my question. This issue has plagued my program since about a week ago, but I only really started to look into this infuriating issue in the past 3 days.
HOW TO FIX: When populating your ListView or GridView data binding image from local disk, don’t use a Stream as the BitmapImage source – use the BitmapImage constructor with a Uri object pointing to your target image.
Here’s how:
`BitmapImage tempBitmap = new BitmapImage(new Uri(currentFile.Path));
photos.Add(tempBitmap);`