Partager via


Show file thumbnails in your Windows Store App

 

If your app has a requirement where you use a filepicker and then show the files that the user selects as a preview/list, chances are you would like the option to show thumbnails of the files.

A quick search tells you that the Windows.Storage.StorageFile.GetThumbnailAsync is the way to go! However, I didn’t find an article which just put things together, so here you go Smile

First things first - here are the screenshots from the sample app I wrote:

clip_image002

clip_image004

clip_image006

If this is not what you’re looking for, you may want to avoid reading the rest of this post - no hard feelings! Smile

If this is what you were looking for, let’s get down to business!

1. Set up the FileOpenPicker, get selected files, get thumbnails of the selected files
 private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
 {
     // 1. Get FileOpenPicker ready
     var picker = new FileOpenPicker();
     picker.ViewMode = PickerViewMode.Thumbnail;
     picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
             
     // 2. Add filters - it's required to have at least one filter
     //    it CANNOT be a wildcard (i.e., no .*)
     picker.FileTypeFilter.Add(".docx");
     picker.FileTypeFilter.Add(".pptx");
     picker.FileTypeFilter.Add(".xlsx");
     picker.FileTypeFilter.Add(".xls");
     picker.FileTypeFilter.Add(".jpg");
     picker.FileTypeFilter.Add(".png");
     picker.FileTypeFilter.Add(".pdf");
  
     // 3. Call the file picker
     var file = await picker.PickMultipleFilesAsync();
  
     if (file != null)
     {
         foreach (var storageFile in file)
         {
             // fileList = new ObservableCollection<SimpleFileInfo>(); in the constructor
             // SimpleFileInfo is a class with a string FileName and a StorageItemThumbnail Thumbnail field.
             fileList.Add(new SimpleFileInfo
             {
                 FileName = storageFile.Name,
                 // 4. Get image thumbnails!!
                 Thumbnail = await storageFile.GetThumbnailAsync(ThumbnailMode.SingleItem)
             });
         }
                 
     }
 }
 
2. Create a converter which converts StorageItemThumbnail to an Image

The following snippet was used from Mike Taulty’s blog post on Making a Simple Photo Viewer in C# and XAML.

 using Windows.Storage.FileProperties;
 using Windows.UI.Xaml.Data;
 using Windows.UI.Xaml.Media;
 using Windows.UI.Xaml.Media.Imaging;
  
 public class ThumbnailToImageConverter : IValueConverter
 {
     public object Convert(object value, Type targetType, object parameter, string language)
     {
         BitmapImage image = null;
  
         if (value != null)
         {
             if (value.GetType() != typeof(StorageItemThumbnail))
             {
                 throw new ArgumentException("Expected a thumbnail");
             }
             if (targetType != typeof(ImageSource))
             {
                 throw new ArgumentException("What are you trying to convert to here?");
             }
             StorageItemThumbnail thumbnail = (StorageItemThumbnail)value;
             image = new BitmapImage();
             image.SetSource(thumbnail);
         }
         return (image);
     }
     public object ConvertBack(object value, Type targetType, object parameter, string language)
     {
         throw new NotImplementedException();
     }
 }  
 
3. Bind the filelist (from step 1) to a ListView (or an Items Control of your choice), and use the converter

XAML:

Declare the Converter as a resource

 <Page.Resources>
     <local:ThumbnailToImageConverter x:Key="ThumbnailToImageConverter" />
 </Page.Resources>

Use it in the ListView

 <ListView Grid.Row="1" x:Name="FileListItemsControl" VerticalAlignment="Top" Height="200" Margin="20" >
     <ListView.ItemsPanel>
         <ItemsPanelTemplate>
             <VirtualizingStackPanel Orientation="Horizontal" />
         </ItemsPanelTemplate>
     </ListView.ItemsPanel>
     <ListView.ItemTemplate>
         <DataTemplate>
           <StackPanel>
              <Image Source="{Binding Thumbnail, Converter={StaticResource ThumbnailToImageConverter}}" Height="150" Width="300" />
              <TextBlock Text="{Binding FileName}" Style="{StaticResource BodyTextBlockStyle}" />
           </StackPanel>
         </DataTemplate>
     </ListView.ItemTemplate>
 </ListView>

C#:

Set the ItemsSource of the ListView to the fileList collection.

 protected override void OnNavigatedTo(NavigationEventArgs e)
 {
     navigationHelper.OnNavigatedTo(e);
     this.FileListItemsControl.ItemsSource = fileList;
 }

That’s it – you should now be able to try it out!

Show me the (full) codez!

Full XAML and C# listing below:

XAML:

 <Page
     x:Name="pageRoot"
     x:Class="DevTest.BasicPage1"
     DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
     xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:local="using:DevTest"
     xmlns:common="using:DevTest.Common"
     xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
     mc:Ignorable="d">
  
     <Page.Resources>
         <local:ThumbnailToImageConverter x:Key="ThumbnailToImageConverter" />
         <x:String x:Key="AppName">File thumbnail sample</x:String>
     </Page.Resources>
   
     <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
         <Grid.ChildrenTransitions>
             <TransitionCollection>
                 <EntranceThemeTransition/>
             </TransitionCollection>
         </Grid.ChildrenTransitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="140"/>
             <RowDefinition Height="*"/>
         </Grid.RowDefinitions>
  
         <!-- Back button and page title -->
         <Grid>
             <Grid.ColumnDefinitions>
                 <ColumnDefinition Width="120"/>
                 <ColumnDefinition Width="*"/>
             </Grid.ColumnDefinitions>
             <Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                         Style="{StaticResource NavigationBackButtonNormalStyle}"
                         VerticalAlignment="Top"
                         AutomationProperties.Name="Back"
                         AutomationProperties.AutomationId="BackButton"
                         AutomationProperties.ItemType="Navigation Button"/>
             <TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
                         IsHitTestVisible="false" TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,30,40"/>
         </Grid>
         <Button Content="Pick files" Margin="114,376,0,452" Grid.Row="1" Click="ButtonBase_OnClick"
                  Width="100" Height="100"/>
         
         <ListView Grid.Row="1" x:Name="FileListItemsControl" VerticalAlignment="Top" Height="200" Margin="20" >
             <ListView.ItemsPanel>
                 <ItemsPanelTemplate>
                     <VirtualizingStackPanel Orientation="Horizontal" />
                 </ItemsPanelTemplate>
             </ListView.ItemsPanel>
             <ListView.ItemTemplate>
                 <DataTemplate>
                     <StackPanel>
                         <Image Source="{Binding Thumbnail, Converter={StaticResource ThumbnailToImageConverter}}" Height="150" Width="300" />
                         <TextBlock Text="{Binding FileName}" Style="{StaticResource BodyTextBlockStyle}" />
                     </StackPanel>
                 </DataTemplate>
             </ListView.ItemTemplate>
         </ListView>
     </Grid>
 </Page>

 

C#:

 using DevTest.Common;
 using System;
 using Windows.UI.Xaml;
 using Windows.UI.Xaml.Controls;
 using Windows.UI.Xaml.Navigation;
  
 namespace DevTest
 {
     using System.Collections.ObjectModel;
  
     using Windows.Storage.FileProperties;
     using Windows.Storage.Pickers;
  
     // Boilerplate stuff - deleting comments to reduce the code snippet size
     public sealed partial class BasicPage1 : Page
     {
  
         private NavigationHelper navigationHelper;
         private ObservableDictionary defaultViewModel = new ObservableDictionary();
  
         // Boilerplate stuff - deleting comments to reduce the code snippet size
         public ObservableDictionary DefaultViewModel
         {
             get { return this.defaultViewModel; }
         }
  
         // Boilerplate stuff - deleting comments to reduce the code snippet size
         public NavigationHelper NavigationHelper
         {
             get { return this.navigationHelper; }
         }
  
         private ObservableCollection<SimpleFileInfo> fileList;
  
         public BasicPage1()
         {
             this.InitializeComponent();
             this.navigationHelper = new NavigationHelper(this);
             this.navigationHelper.LoadState += navigationHelper_LoadState;
             this.navigationHelper.SaveState += navigationHelper_SaveState;
             fileList = new ObservableCollection<SimpleFileInfo>();
         }
  
         // Boilerplate stuff - deleting comments to reduce the code snippet size
         private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
         {
         }
  
         // Boilerplate stuff - deleting comments to reduce the code snippet size
         private void navigationHelper_SaveState(object sender, SaveStateEventArgs e)
         {
         }
  
         // Boilerplate stuff - deleting comments to reduce the code snippet size
         protected override void OnNavigatedTo(NavigationEventArgs e)
         {
             navigationHelper.OnNavigatedTo(e);
             this.FileListItemsControl.ItemsSource = fileList;
         }
  
         protected override void OnNavigatedFrom(NavigationEventArgs e)
         {
             navigationHelper.OnNavigatedFrom(e);
         }
  
         // OUR CODE!!!
         private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
         {
             // 1. Get FileOpenPicker ready
             var picker = new FileOpenPicker();
             picker.ViewMode = PickerViewMode.Thumbnail;
             picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
             
             // 2. Add filters - it's required to have at least one filter
             //    it CANNOT be a wildcard (i.e., no .*)
             picker.FileTypeFilter.Add(".docx");
             picker.FileTypeFilter.Add(".pptx");
             picker.FileTypeFilter.Add(".xlsx");
             picker.FileTypeFilter.Add(".xls");
             picker.FileTypeFilter.Add(".jpg");
             picker.FileTypeFilter.Add(".png");
             picker.FileTypeFilter.Add(".pdf");
  
             // 3. Call the file picker
             var file = await picker.PickMultipleFilesAsync();
  
             if (file != null)
             {
                 foreach (var storageFile in file)
                 {
                     // fileList = new ObservableCollection<SimpleFileInfo>(); in the constructor
                     // SimpleFileInfo is a class with a string FileName and a StorageItemThumbnail Thumbnail field.
                     fileList.Add(new SimpleFileInfo
                     {
                         FileName = storageFile.Name,
                         // 4. Get image thumbnails!!
                         Thumbnail = await storageFile.GetThumbnailAsync(ThumbnailMode.SingleItem)
                     });
                 }
  
             }
         }
     }
  
     public class SimpleFileInfo
     {
         public string FileName { get; set; }
  
         public StorageItemThumbnail Thumbnail { get; set; }
     }
 }

 

Thanks for reading!

Amar

PS: You can follow me on twitter at “_amarnit”, where I share some quick tips/learning at times!