Access to Windows Phone 7 Camera Roll from a Silverlight App …

Or “Why is my RootPictureAlbum null?”

Download the code for this example.

In order to get programmatic access to the available media libraries on Windows Phone 7, you need to use some XNA libraries even in a Silverlight application.  I will give an example of how to use legal APIs from XNA.  I will also utilize the WP Connect tool that was part of the October 2010 Update to the Developer Tools to test my application on a WP7 device.

The fist thing to do is create a blank Windows Phone 7 application. Add a reference to the Microsoft.Xna.Framework assembly to that application.

image

This is not a a violation of the Certification Requirements.  As of this writing, section 4.2.5 of the Certification Requirements forbids calling APIs in Microsoft.Xna.Framework.Game or Microsoft.Xna.Framework.Graphics.  We will be using Microsoft.Xna.Framework.Media only.

I’ve just created a toy example to do this, but it is sufficient for our purposes here.  I should note that this application will not work in the Emulator.  You have to have a device to run it.  Here’s what it looks like …

image

The relevant XAML to create such a beautiful test app is …

 <Grid x:Name="LayoutRoot" Background="Transparent">
     <Grid.RowDefinitions>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="*"/>
     </Grid.RowDefinitions>
  
     <!--TitlePanel contains the name of the application and page title-->
     <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
         <TextBlock x:Name="ApplicationTitle" Text="Media Libraries Sample" Style="{StaticResource PhoneTextNormalStyle}"/>
         <Button Height="100" Content="Go" Click="Button_Click" />
     </StackPanel>
  
     <!--ContentPanel - place additional content here-->
     <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  
         <ListBox x:Name="MainListBox" ItemsSource="{Binding Pics, Mode=OneWay}">
             <ListBox.ItemTemplate>
                 <DataTemplate>
                     <StackPanel Orientation="Horizontal" Height="132">
                         <Image Source="{Binding ImageUrl}" VerticalAlignment="Top" Margin="0,10,8,0"/>
                         <TextBlock Text="{Binding ShortName}" Foreground="#FFC8AB14" FontSize="28" />
                     </StackPanel>
                 </DataTemplate>
             </ListBox.ItemTemplate>
         </ListBox>
     </Grid>
 </Grid>

In our MainPage.xaml.cs, we will add a using statement for Microsoft.Xna.Framework.Media as well as System.Windows.Media.Imaging as we will be using the BitmapImage class.

 using Microsoft.Xna.Framework.Media;
 using System.Windows.Media.Imaging;

I also have an irrelevant helper class (aka ViewModel ZING!) …

 public class PicSample
 {
     public BitmapImage ImageUrl { get; set; }
     public string ShortName { get; set; }
 }

Where the rubber hits the road, we will be making use of the following classes: MediaLibrary, PictureAlbum, PictureAlbumCollection and some magic, non-localized string constants (more on that later).

Add some quick set-up stuff to our MainPage class for DataBinding and all that good stuff …

 public MainPage()
 {
     InitializeComponent();
  
     this.DataContext = this;
 }
  
 public IEnumerable<PicSample> Pics
 {
     get { return _pics; }
 }
  
 private ObservableCollection<PicSample> _pics = new ObservableCollection<PicSample>();

I’ve written about Data Binding in the past, so I won’t repeat that here.  The magic happens in our button handler …

 private void Button_Click(object sender, RoutedEventArgs e)
 {
     // Work around for known bug in the media framework.  Hits the static constructors
     // so the user does not need to go to the picture hub first.
     MediaPlayer.Queue.ToString();
  
     MediaLibrary ml = null;
     PictureAlbum cameraRoll = null;
     PictureAlbum savedPics = null;
  
     foreach (MediaSource source in MediaSource.GetAvailableMediaSources())
     {
         if (source.MediaSourceType == MediaSourceType.LocalDevice)
         {
             ml = new MediaLibrary(source);
             PictureAlbumCollection allAlbums = ml.RootPictureAlbum.Albums;
  
             foreach (PictureAlbum album in allAlbums)
             {
                 if (album.Name == "Camera Roll")
                 {
                     cameraRoll = album;
                 }
  
                 if (album.Name == "Saved Pictures")
                 {
                     savedPics = album;
                 }
             }
         }
     }
  
     foreach (Picture p in cameraRoll.Pictures.Take(3))
     {
         BitmapImage b = new BitmapImage();
         b.SetSource(p.GetThumbnail());
         _pics.Add(new PicSample() { ImageUrl = b, ShortName = p.Name });
     }
 }

inigo

“Let me 'splain.  [pause]   No, there is too much. Let me sum up.”

You may have noticed this rather dubious line of code …

 MediaPlayer.Queue.ToString();

This is a work-around for a known issue related to static constructors.  Things can work just fine without this code if the user happens to go to the Picture Hub first.   That will initialize the class and allow the RootPictureAlbum property on the MediaLibrary to be not null.  Of course, you cannot depend on what the user is going to do or not going to do.  So, I’ve added a no-op that has the side-effect of ensuring that all the objects I’m about to use are all setup and initialized nicely.  Side-effects FTW!

But there is more magic yet to come!  You may have noticed a bit of smell here …

 if (album.Name == "Camera Roll")
 {
     cameraRoll = album;
 }

Hard coded strings! Hard coded strings! Alert! Alert!

DISCLAIMER: I am told that these strings are not localized and as such will remain the same regardless of the language and culture of the phone device.  I’ve not verified that, so do your culture testing!

In order to test this application, you cannot use the Zune client.  You have to plug your device in, let Zune come up, detect your device and then quit Zune and use WP Connect.  The media libraries will be null if you have Zune attached.

If all is well, when you run this application on a device, you should see the “top” three pictures from your camera roll.  A little magic, a little faith and boom, pictures!