2

Context

I am attempting to display images from a directory inside the user's local pictures folder (e.g. C:\Users\Username\Pictures\The Folder) into a GridView.

I am using a class for the image (this is the source for the GridView):

public class SpotlightImage
    {
        public string ID { get; set; }

        public string Name { get; set; }

        public string FileSource { get; set; }
    }

The XAML for the GridView is below:

<GridView
            Padding="{StaticResource MediumLeftRightMargin}"
            animations:Connected.ListItemElementName="thumbnailImage"
            animations:Connected.ListItemKey="galleryAnimationKey"
            IsItemClickEnabled="True"
            ItemClick="ImagesGridView_ItemClick"
            ItemsSource="{x:Bind Source, Mode=OneWay}"
            RightTapped="ImagesGridView_RightTapped"
            SelectionMode="None">
            <GridView.ItemTemplate>
                <DataTemplate x:DataType="models:SpotlightImage">
                    <Image
                        x:Name="thumbnailImage"
                        AutomationProperties.Name="{x:Bind Name}"
                        Source="{x:Bind FileSource}"
                        Style="{StaticResource ThumbnailImageStyle}"
                        ToolTipService.ToolTip="{x:Bind Name}" />
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>

The C# for populating the source is below (I realise that it is most likely unnecessary to use the parallel foreach, however, I am using it for consistency with other code in the project):

private async void ImagesPage_OnLoaded(object sender, RoutedEventArgs e)
        {
            Source.Clear();

            storageFiles = new List<Windows.Storage.StorageFile>();

            List<string> SavedWallpapers = await RetrieveAllSavedWallpapers.Main(); //Retrieves image names

            galleryData = new List<SpotlightImage>();

            Parallel.ForEach(SavedWallpapers, spotlightFile =>
            {
                imgFileFunction(spotlightFile);
            });

            async void imgFileFunction(string spotlightFile)
            {
                try
                {
                    //StorageReferences.WallpaperSaveStorage is a StorageFolder variable for the images directory being accessed
                    Windows.Storage.StorageFile file = await StorageReferences.WallpaperSaveStorage.GetFileAsync(spotlightFile);

                    storageFiles.Add(file);

                    var img = new SpotlightImage()
                    {
                        ID = file.DisplayName,
                        FileSource = file.Path,
                        Name = file.DisplayName
                    };

                    galleryData.Add(img);

                    await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                    () =>
                    {
                        Source.Add(img);

                        Debug.WriteLine("IMAGE ADDED: " + img.Name);
                    }
                    );
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("MULTITHREADED ERROR: " + ex.Message);
                }
            }
        }

The Problem

The GridView displays empty squares instead of images. The correct number of 'images' appear, but they are blank.

What I've tried

I have looked at similar issues on StackOverflow and tried the following:

  1. Using a UriSource instead of source (The same issue persists)
  2. Looked at the code (I have used the exact same code somewhere else in my project and it works there. The only difference is that a different folder is being accessed)
  3. Checked permissions (I have used this exact directory in previous code with no issue)

Notes:

My UWP application already has broadFileSystemAccess (It was necessary for my application's purpose).

I have a FlipView which is accessing the same files and experiencing the exact same issue.

I already have the exact same code running perfectly fine elsewhere in my project, the only difference is the folder being accessed. This led me to believe that the issue was permissions, but my application has broadFileSystemAccess. So this shouldn't be the issue (?)

As you can probably tell, I am relatively new to UWP. So if there is some obvious permission issues or likewise, please go easy on me :)

3 Answers3

3

Based on the Image.Source property,in the Setting Source in XAML part of the document, it mentions that when you are setting the Source property value as a URI string that describes the location of the source image file, actually, it calls the equivalent of the BitmapImage(Uri) constructor to create a BitmapImage object for the Image.Source property.

I made a simple test that creates a BitmapImage object directly from the file path( files out of the application). The BitmapImage object shows nothing if it is set to Image control. This is the same behavior that you got. If the files are a part of the app package, then it works correctly.

As you mentioned that you are using full file system access, I guess it means the broadFileSystemAccess capability, right? This capability only works for APIs in the Windows.Storage namespace not work for APIs like BitmapImage(URI).

So the reason for the behavior should be that when the app uses the file path that is not part of the app package as the URI for the BitmapImage object, the BitmapImage object is not created correctly. Trying to open the file as steam and set it to the BitmapImage object is the correct way to open an image file which locates out of the app package.

Roy Li - MSFT
  • 8,043
  • 1
  • 7
  • 13
  • Thank you for that clear explanation. I'm going to accept my own answer as it has the link to the other post with the instructions, but I have edited it to reference your answer. – Creative Coder Apr 13 '22 at 06:58
2

After hours of scouring the internet, I came across this post from 9 years ago. After refitting the relevant code to use Bitmaps instead of jpgs, everything is working. The only downside is the unusual aliasing (jagged edges) in the bitmap image when displayed in the GridView. At least it is working though.

One thing I will never understand though: why on earth did I have to use a Bitmap?

Anyway, hopefully this helps some poor random programmer who will see this answer 9 years from now.

Edit: This answer from Roy Li was a wonderful explanation of why I had this issue, and why doing the bitmap manually solved it.

0

Try using the ImageEx component from the UWP CommunityToolkit. It will handle all the loading and cacheing stuff for you

  1. Here's the Docs https://learn.microsoft.com/en-us/windows/communitytoolkit/getting-started
  2. Here's the sample app https://aka.ms/windowstoolkitapp

Here is a screenshot from the samples app of the ImageEx control enter image description here

Lance McCarthy
  • 1,884
  • 1
  • 20
  • 40
  • ImageEx does not appear to be working for me. I followed the documentation (I installed the extension and added the xmlns attribute to the top of the page). However, when I add the ImageEx control code (I even tried literally copying and pasting from the sample app) it tells me 'The name "ImageEx" does not exist in the namespace "using:Microsoft.Toolkit.Uwp.UI.Controls"' – Creative Coder Apr 12 '22 at 05:43