So on a recent Windows 8 store app project, we wanted to let the user pick images from his hard drive to use them inside the app.
But with Windows 8 store apps we are a bit restricted on rights to get a hold on files anywhere on the pc’s hard drive. Sure when you select the file you can read it, but when the app restarts that location could be no longer available to the app itself due to rights restrictions.
So, how could we solve this? We could store the images binary inside some sort of database… but for our app that would be a bit too much. Other solution is just using the default Picture library that is available on the pc itself!
It’s easy to give the app rights to this folder… it’s right there in the Capabilities section all you have to do is switch it on!
With that in place we only needed to create an image control that would allow us to use a normal string, representing the path to the location of the image, as source. But the control should also let the user select images and copy those over to the picture library so we can reuse them later!
So let me introduce to you the PictureLibraryImage control!
It’s a user control that contains an Image and has some extra Dependency Properties.
The xaml looks like this – note there are 2 fading animations, they are used to let the Placeholder image fade out and the Source image fade in, after it has been loaded!
1 |
<span id="lnum1" style="color: #606060"> 1:</span> <UserControl x:Name=<span style="color: #006080">"PictureLibImageControl"</span> |
1 |
<span id="lnum2" style="color: #606060"> 2:</span> x:Class=<span style="color: #006080">"PictureLibraryImageControl.Controls.PictureLibImage"</span> |
1 |
<span id="lnum3" style="color: #606060"> 3:</span> xmlns=<span style="color: #006080">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span> |
1 |
<span id="lnum4" style="color: #606060"> 4:</span> xmlns:x=<span style="color: #006080">"http://schemas.microsoft.com/winfx/2006/xaml"</span> |
1 |
<span id="lnum5" style="color: #606060"> 5:</span> xmlns:local=<span style="color: #006080">"using:PictureLibraryImageControl.Controls"</span> |
1 |
<span id="lnum6" style="color: #606060"> 6:</span> xmlns:d=<span style="color: #006080">"http://schemas.microsoft.com/expression/blend/2008"</span> |
1 |
<span id="lnum7" style="color: #606060"> 7:</span> xmlns:mc=<span style="color: #006080">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span> |
1 |
<span id="lnum8" style="color: #606060"> 8:</span> mc:Ignorable=<span style="color: #006080">"d"</span> |
1 |
<span id="lnum9" style="color: #606060"> 9:</span> d:DesignHeight=<span style="color: #006080">"300"</span> |
1 |
<span id="lnum10" style="color: #606060"> 10:</span> d:DesignWidth=<span style="color: #006080">"400"</span>> |
1 |
<span id="lnum11" style="color: #606060"> 11:</span> <Grid> |
1 |
<span id="lnum12" style="color: #606060"> 12:</span> <Grid.Resources> |
1 |
<span id="lnum13" style="color: #606060"> 13:</span> <Storyboard x:Name=<span style="color: #006080">"ImageFadeOut"</span>> |
1 |
<span id="lnum14" style="color: #606060"> 14:</span> <FadeOutThemeAnimation Storyboard.TargetName=<span style="color: #006080">"Image"</span> /> |
1 |
<span id="lnum15" style="color: #606060"> 15:</span> </Storyboard> |
1 |
<span id="lnum16" style="color: #606060"> 16:</span> <Storyboard x:Name=<span style="color: #006080">"ImageFadeIn"</span>> |
1 |
<span id="lnum17" style="color: #606060"> 17:</span> <FadeInThemeAnimation Storyboard.TargetName=<span style="color: #006080">"Image"</span> /> |
1 |
<span id="lnum18" style="color: #606060"> 18:</span> </Storyboard> |
1 |
<span id="lnum19" style="color: #606060"> 19:</span> </Grid.Resources> |
1 |
<span id="lnum20" style="color: #606060"> 20:</span>  |
1 |
<span id="lnum21" style="color: #606060"> 21:</span> <Image x:Name=<span style="color: #006080">"Image"</span> |
1 |
<span id="lnum22" style="color: #606060"> 22:</span> Source=<span style="color: #006080">"{Binding ElementName=PictureLibImageControl, Path=Placeholder}"</span> |
1 |
<span id="lnum23" style="color: #606060"> 23:</span> Height=<span style="color: #006080">"{Binding ElementName=PictureLibImageControl, Path=ActualHeight}"</span> |
1 |
<span id="lnum24" style="color: #606060"> 24:</span> Width=<span style="color: #006080">"{Binding ElementName=PictureLibImageControl, Path=ActualWidth}"</span> |
1 |
<span id="lnum25" style="color: #606060"> 25:</span> Tapped=<span style="color: #006080">"OnImageTapped"</span> |
1 |
<span id="lnum26" style="color: #606060"> 26:</span> /> |
1 |
<span id="lnum27" style="color: #606060"> 27:</span> </Grid> |
1 |
<span id="lnum28" style="color: #606060"> 28:</span> </UserControl> |
The properties we are introducing are:
- Placeholder : we use this to show a dummy image when there has no source been set yet
- Source : the path to an image inside the picture library
- FolderName : the name for the folder we use to put the user selected images
When you place the control in your app and run the app, you can tap on it to get a hold of a FilePicker, this will let the user choose an image! When an image is chosen we copy it over to the given FolderName location inside the Picture library… the code looks like this:
1 |
<span id="lnum1" style="color: #606060"> 1:</span> <span style="color: #0000ff">private</span> async <span style="color: #0000ff">void</span> OnImageTapped(<span style="color: #0000ff">object</span> sender, TappedRoutedEventArgs e) |
1 |
<span id="lnum2" style="color: #606060"> 2:</span> { |
1 |
<span id="lnum3" style="color: #606060"> 3:</span> FileOpenPicker openPicker = <span style="color: #0000ff">new</span> FileOpenPicker(); |
1 |
<span id="lnum4" style="color: #606060"> 4:</span> openPicker.ViewMode = PickerViewMode.Thumbnail; |
1 |
<span id="lnum5" style="color: #606060"> 5:</span> openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; |
1 |
<span id="lnum6" style="color: #606060"> 6:</span> openPicker.FileTypeFilter.Add(<span style="color: #006080">".jpg"</span>); |
1 |
<span id="lnum7" style="color: #606060"> 7:</span> openPicker.FileTypeFilter.Add(<span style="color: #006080">".jpeg"</span>); |
1 |
<span id="lnum8" style="color: #606060"> 8:</span> openPicker.FileTypeFilter.Add(<span style="color: #006080">".png"</span>); |
1 |
<span id="lnum9" style="color: #606060"> 9:</span> StorageFile file = await openPicker.PickSingleFileAsync(); |
1 |
<span id="lnum10" style="color: #606060"> 10:</span> <span style="color: #0000ff">if</span> (file != <span style="color: #0000ff">null</span>) |
1 |
<span id="lnum11" style="color: #606060"> 11:</span> { |
1 |
<span id="lnum12" style="color: #606060"> 12:</span> <span style="color: #008000">// Application now has read/write access to the picked file </span> |
1 |
<span id="lnum13" style="color: #606060"> 13:</span> <span style="color: #0000ff">using</span> (await _lock.LockAsync()) |
1 |
<span id="lnum14" style="color: #606060"> 14:</span> { |
1 |
<span id="lnum15" style="color: #606060"> 15:</span> <span style="color: #0000ff">byte</span>[] buffer = <span style="color: #0000ff">null</span>; |
1 |
<span id="lnum16" style="color: #606060"> 16:</span> <span style="color: #0000ff">using</span> (var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) |
1 |
<span id="lnum17" style="color: #606060"> 17:</span> { |
1 |
<span id="lnum18" style="color: #606060"> 18:</span> var reader = <span style="color: #0000ff">new</span> DataReader(stream.GetInputStreamAt(0)); |
1 |
<span id="lnum19" style="color: #606060"> 19:</span> buffer = <span style="color: #0000ff">new</span> <span style="color: #0000ff">byte</span>[stream.Size]; |
1 |
<span id="lnum20" style="color: #606060"> 20:</span> await reader.LoadAsync((<span style="color: #0000ff">uint</span>)stream.Size); |
1 |
<span id="lnum21" style="color: #606060"> 21:</span> reader.ReadBytes(buffer); |
1 |
<span id="lnum22" style="color: #606060"> 22:</span> } |
1 |
<span id="lnum23" style="color: #606060"> 23:</span>  |
1 |
<span id="lnum24" style="color: #606060"> 24:</span> StorageFile selectedPicture = <span style="color: #0000ff">null</span>; |
1 |
<span id="lnum25" style="color: #606060"> 25:</span> <span style="color: #0000ff">if</span> (!<span style="color: #0000ff">string</span>.IsNullOrEmpty(<span style="color: #0000ff">this</span>.FolderName)) |
1 |
<span id="lnum26" style="color: #606060"> 26:</span> { |
1 |
<span id="lnum27" style="color: #606060"> 27:</span> StorageFolder PosPicFolder = await KnownFolders.PicturesLibrary.CreateFolderAsync(<span style="color: #0000ff">this</span>.FolderName, CreationCollisionOption.OpenIfExists); |
1 |
<span id="lnum28" style="color: #606060"> 28:</span> selectedPicture = await PosPicFolder.CreateFileAsync(file.Name, CreationCollisionOption.OpenIfExists); |
1 |
<span id="lnum29" style="color: #606060"> 29:</span> } |
1 |
<span id="lnum30" style="color: #606060"> 30:</span> <span style="color: #0000ff">else</span> |
1 |
<span id="lnum31" style="color: #606060"> 31:</span> selectedPicture = await KnownFolders.PicturesLibrary.CreateFileAsync(file.Name, CreationCollisionOption.OpenIfExists); |
1 |
<span id="lnum32" style="color: #606060"> 32:</span>  |
1 |
<span id="lnum33" style="color: #606060"> 33:</span> await FileIO.WriteBytesAsync(selectedPicture, buffer); |
1 |
<span id="lnum34" style="color: #606060"> 34:</span> <span style="color: #0000ff">this</span>.Source = selectedPicture.Path; |
1 |
<span id="lnum35" style="color: #606060"> 35:</span> } |
1 |
<span id="lnum36" style="color: #606060"> 36:</span> } |
1 |
<span id="lnum37" style="color: #606060"> 37:</span> } |
Now comes the last part of our control! We have to be able to use a string pointing to a file inside the picture library as source…
This is actually very easy with the Source dependency property in place and the Picture Library capability. We only have to read out the file and set it as BitmapImage to the image ssource inside the control! The code for this is
1 |
<span id="lnum1" style="color: #606060"> 1:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> async <span style="color: #0000ff">void</span> SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
1 |
<span id="lnum2" style="color: #606060"> 2:</span> { |
1 |
<span id="lnum3" style="color: #606060"> 3:</span> var control = (PictureLibImage)d; |
1 |
<span id="lnum4" style="color: #606060"> 4:</span> var file = await StorageFile.GetFileFromPathAsync((<span style="color: #0000ff">string</span>)e.NewValue); |
1 |
<span id="lnum5" style="color: #606060"> 5:</span> <span style="color: #0000ff">if</span> (file != <span style="color: #0000ff">null</span>) |
1 |
<span id="lnum6" style="color: #606060"> 6:</span> { |
1 |
<span id="lnum7" style="color: #606060"> 7:</span> <span style="color: #0000ff">using</span> (var stream = await file.OpenAsync(FileAccessMode.Read)) |
1 |
<span id="lnum8" style="color: #606060"> 8:</span> { |
1 |
<span id="lnum9" style="color: #606060"> 9:</span> var bitmapImage = <span style="color: #0000ff">new</span> BitmapImage(); |
1 |
<span id="lnum10" style="color: #606060"> 10:</span> await bitmapImage.SetSourceAsync(stream); |
1 |
<span id="lnum11" style="color: #606060"> 11:</span>  |
1 |
<span id="lnum12" style="color: #606060"> 12:</span> bitmapImage.ImageOpened += (sender, args) => control.LoadImage(bitmapImage); |
1 |
<span id="lnum13" style="color: #606060"> 13:</span> } |
1 |
<span id="lnum14" style="color: #606060"> 14:</span> } |
1 |
<span id="lnum15" style="color: #606060"> 15:</span> } |
Only thing left to do is use it in your project… the source can be binded to some MVVM property of course.
1 |
<span id="lnum1" style="color: #606060"> 1:</span> <controls:PictureLibImage x:Name=<span style="color: #006080">"PictureLibImage"</span> |
1 |
<span id="lnum2" style="color: #606060"> 2:</span> Placeholder=<span style="color: #006080">"/Assets/placeholder_250.png"</span> |
1 |
<span id="lnum3" style="color: #606060"> 3:</span> FolderName=<span style="color: #006080">"PictureLibImageTest"</span> |
1 |
<span id="lnum4" style="color: #606060"> 4:</span> Source=<span style="color: #006080">"E:\ZuneMedia\Pictures\SistersOfMercyWhite500x500.jpg"</span> |
1 |
<span id="lnum5" style="color: #606060"> 5:</span> Height=<span style="color: #006080">"250"</span> |
1 |
<span id="lnum6" style="color: #606060"> 6:</span> Width=<span style="color: #006080">"250"</span> |
1 |
<span id="lnum7" style="color: #606060"> 7:</span> /> |
Let me get one thing straight, this is not by any chance the most elegant solution… but for our needs it served the purpose very well.
Just go through the code, maybe there are other things you could reuse instead of the actual control itself 🙂
Everything is up on my Github here… so download, use and any suggestions or improvements are welcome!
One thought on “Picture library image control for Windows 8 store apps”