Windows 8 Apps: Creating Picture Library Viewer using XAML GridView and C#

When building Windows Store Apps, WinRT provides an easy mechanism to work with operating system special folders like Pictures, Videos, Music etc. WinRT has built-in APIs to access these special folders and makes it easier for developers to safely access files in here.

APIs to access files and folder groups are defined in the Windows.Storage namespace. This provides various classes to manage files, folders and application settings. One of the classes under this namespace is KnownFolders, which provides access to common locations that acts as a repository for local user content/files. Along with these libraries, it also includes removable devices, media servers etc.

A class to take note of under ‘KnownFolders’ namespace is PicturesLibrary. This class represents the Picture library on the device and can enumerate all the images in them.

Today, we will see how to work with the PicturesLibrary class and display all the Pictures (as Thumbnails) in the GridView. We will be using C# and XAML. In the following code, along with the PicturesLibrary class, we also use the following:

- QueryOptions: This is used to specify parameters for search query to iterate through the storage folder’s contents.

- FileInformationFactory:
  • This class is used to load files and folders information based upon the query files using the QueryOptions class.
  • The result is then used to bind with the UI controls like ListView, GridView etc.
  • The result is extracted by the method ‘GetVirtulizedFilesVector’.
  • The return value from this method is of the type object. This is the virtualized vector of IStorageItemInformation.
Step 1: Open VS 2012 and create a new Windows Store App, using C#, name it as ‘Store_CS_PictureViewer’.

Step 2: In the MainPage.Xaml add the GridView:

<TextBlock HorizontalAlignment="Center"
   Margin="10,10,0,0"
   TextWrapping="Wrap"
   Text="Image Viewer"
   VerticalAlignment="Top"
   Height="68"
   Width="1334"
   FontWeight="Bold"
   FontFamily="Segoe UI" FontSize="50"/>
<GridView x:Name="gvPictures"
  HorizontalAlignment="Left"
  Margin="21,118,0,0"
  VerticalAlignment="Top"
  Width="1334" Height="640" />

Step 3: In the Loaded event add the below code, this will query to the picture library and get the picture information:

/// <summary>
/// The method queries the
/// Picture Library with all its sub folders and
/// reads all pictures
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Page_Loaded_1(object sender, RoutedEventArgs e)
{
//Define thr query to iterate thriugh all the subfolders
var pictureQueryOptions = new QueryOptions();
//Read through all the subfolders.
pictureQueryOptions.FolderDepth = FolderDepth.Deep;

//Apply the query on the PicturesLibrary
var pictureQuery = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(pictureQueryOptions);
//
var picturesInformation = new FileInformationFactory(pictureQuery, ThumbnailMode.PicturesView);
picturesSource.Source = picturesInformation.GetVirtualizedFilesVector();
}

Step 4: Now one of the important things here is that we are going to show all images in the GridView using ‘Image’ XAML element. Since the images are extracted as ‘Thumbnail’, we need to convert this to an Image source so that it can be bound to the Image element. To achieve this, add a new converter class which implements IValueConverter interface (this is coming from the same old WPF IValueConverter). The code is as below:

/// <summary>
/// The converter class used to display images
/// </summary>
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object    parameter, string culture)
{
  if (value != null)
  {
   var img = (IRandomAccessStream)value;
   var picture = new BitmapImage();
   picture.SetSource(img);
   return picture;
  }
  return DependencyProperty.UnsetValue;
}

public object ConvertBack(object value, Type targetType, object parameter, string culture)
{
  throw new NotImplementedException();
}
}

  
Step 5: In the MainPage.xaml, add the following DataTemplate and also define the ImageConverter object as below:

<Page.Resources>
    <local:ImageConverter x:Key="imageConveter"/>
    <DataTemplate x:Key="imageTemplate">
        <Grid Width="190" Height="130">
            <Image Source="{Binding Path=Thumbnail,
            Converter={StaticResource imageConverter}}"
            Stretch="None" Width="200" Height="200"/>
        </Grid>
    </DataTemplate>
    <CollectionViewSource
        x:Name="picturesSource"/>
</Page.Resources>

  
The DataTemplate defines an image which is bound to the ‘Thumbnail’ property received after querying the PicturesLibrary. The Converter will accept the thumbnail and then set it as a source of the image element.

Step 6: Change the GridView in XAML with ItemsSource and ItemTemplate property as below:

<GridView x:Name="gvPictures" HorizontalAlignment="Left" Margin="21,118,0,0"
  VerticalAlignment="Top" Width="1334" Height="640"
   ItemsSource="{Binding Source={StaticResource picturesSource}}"
   ItemTemplate="{StaticResource imageTemplate}"/>

Step 7: Click on the Manifest file and set the Capability for accessing the PicturesLibrary as below:

capability

Run the application and the result will be a grid of images from your Pictures folder.

result

Conclusion

Folder access in WinRT is really restricted to an App’s sandbox location. The KnownFolders abstraction lets end users store common data accessible to all Store apps. However, Store Apps need to declare explicit capability, thus giving users a direct say in their selection of apps that they want to trust with their data. This makes file sharing relatively safer amongst Store apps, while providing a nice abstraction to access them at the developer end.

The code can be downloaded from Github https://github.com/devcurry/winrt-known-folders

References

Windows 8 API documentation




About The Author

Mahesh Sabnis is a Microsoft MVP having over 18 years of experience in IT education and development. He is a Microsoft Certified Trainer (MCT) since 2005 and has conducted various Corporate Training programs for .NET Technologies (all versions). He also blogs regularly at DotNetCurry.com. Follow him on twitter @maheshdotnet

1 comment:

Unknown said...

Thanks for the tutorial. Its a great help.

Quick question. on the Gridview im able to select a picture. how do I delete the picture from storage. I don't get a reference to the picture from gridview.selectedItem