MediaLibrary songs and artwork both on emulator and device

MediaLibrary songs and artwork both on emulator and device

Recently I found a question online concerning the songs from the Windows Phone media library. Basically the problem was how to test the song retrieval on the emulator (where you actually don’t have your library), and how to get the artwork, which is related to the album, not the particular song. The process is explained in this post, and shows how to bind the collection of songs (artwork included) to a ListBox, and what happens when you try to do that in the emulator.

Your device probably has music in the media library. It could be filled with songs that are part of albums, which have a certain album artwork. Now, how do you connect those, and display the list of songs (artist, title, duration and artwork)? The solution is not straightforward because you can bind the ListBox to the collection of songs, but how do you get the artwork? The artwork is the property of Album class. So, you need to get the SongCollection collection from the MediaLibrary object, and bind that collection to the ItemsSource of the ListBox. Each Song from the SongCollection has an Album property, and the Album has the GetArtwork method which returns the stream that contains the album art image data, and the bool property HasArt that is true if the Album has associated album art, and false otherwise. So start be creating a new Windows Phone Mango project, and add the following references:

using Microsoft.Xna.Framework;  
using Microsoft.Xna.Framework.Input;  
using Microsoft.Xna.Framework.Media;  
using System.Windows.Media.Imaging;  
using System.ComponentModel;  
using System.Collections.ObjectModel;  

Add the ListBox and format it for the Song objects:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">  
      <ListBox Name="listBoxSongs">
          <ListBox.ItemTemplate>
              <DataTemplate>
                  <Grid>
                      <Grid.RowDefinitions>
                          <RowDefinition />
                          <RowDefinition />
                      </Grid.RowDefinitions>
                      <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="120"/>
                          <ColumnDefinition Width="260"/>
                          <ColumnDefinition Width="Auto"/>
                      </Grid.ColumnDefinitions>
                      <Image Margin="8"
                             Grid.Row="0"
                             Grid.Column="0"
                             Grid.RowSpan="2"
                             Source="{Binding Image}"/>
                      <TextBlock Grid.Row="0"
                                 VerticalAlignment="Center"
                                 Grid.Column="1"
                                 Foreground="{StaticResource PhoneAccentBrush}"
                                 Text="{Binding Title}"
                                 TextWrapping="Wrap"
                                 FontSize="24"/>
                      <TextBlock Grid.Row="1"
                                 VerticalAlignment="Center"
                                 Grid.Column="1"
                                 Text="{Binding Artist}"
                                 TextWrapping="Wrap"/>
                      <TextBlock Grid.Row="0"
                                 VerticalAlignment="Center"
                                 Grid.Column="2"
                                 Grid.RowSpan="2"
                                 Text="{Binding Duration}" />
                  </Grid>
              </DataTemplate>
          </ListBox.ItemTemplate>
      </ListBox>
  </Grid>

Could you simply bind this to the collection of songs? (SongCollection)

Well, not really. The solution I find to be the simplest and more efficient is creating the MySongs class, like this one:

public class MySong : INotifyPropertyChanged  
          {
              private BitmapImage image;
              private String title;
              private String artist;
              private String duration;

              public String Duration
              {
                  get { return duration; }
                  set
                  {
                      duration = value;
                      NotifyPropertyChanged("Duration");
                  }
              }

              public BitmapImage Image
              {
                  get { return image; }
                  set
                  {
                      image = value;
                      NotifyPropertyChanged("Image");
                  }
              }

              public String Title
              {
                  get { return title; }
                  set
                  {
                      title = value;
                      NotifyPropertyChanged("Title");
                  }
              }

              public String Artist
              {
                  get { return artist; }
                  set
                  {
                      artist = value;
                      NotifyPropertyChanged("Artist");
                  }
              }

              public event PropertyChangedEventHandler PropertyChanged;
              protected virtual void NotifyPropertyChanged(String propertyName)
              {
                  PropertyChangedEventHandler handler = PropertyChanged;
                  if (null != handler)
                  {
                      handler(this, new PropertyChangedEventArgs(propertyName));
                  }
              }
          }

This way, you can create an ObservableCollection of MySong object, and bind it to the ListBox. Now, in the MainPage constructor, load the Songs from the Media Library and populate the MySongs observable collection with the songs and their artwork:

public partial class MainPage : PhoneApplicationPage  
      {
          // Constructor

          ObservableCollection<MySong> mySongs = new ObservableCollection<MySong>();

          public MainPage()
          {
              InitializeComponent();

              MediaLibrary library = new MediaLibrary();
              SongCollection songs = library.Songs;

              foreach (Song song in songs)
              {
                  mySongs.Add(new MySong()
                  {
                      Artist = song.Artist.ToString(),
                      Title = song.Name,
                      Duration = (new DateTime(song.Duration.Ticks)).ToString("mm:ss")
                  });
                  if (song.Album.HasArt)
                  {
                      BitmapImage img = new BitmapImage();
                      img.SetSource(song.Album.GetAlbumArt());
                      mySongs.Last().Image = img;
                  }
                  else
                      mySongs.Last().Image = new BitmapImage(new Uri("noArt.png", UriKind.Relative));
              }

              listBoxSongs.ItemsSource = mySongs;

          }

If the album has artwork, then use it, and if not, use a generic image such as the one I’ve created – a simple grey square image with a red X called noArt.png.

What happens if you try to run this code on emulator, where you don’t have your music library? Luckily, there’s something on the emulator – a few 15 to 30 seconds songs, which unfortunately don’t have artwork, but that’s what the noArt.png file is for.

mediaLib

If you run it on your Windows Phone device, you will get the songs from your library with the matching artwork! :)

Igor Ralic

igor ralic

View Comments
Microsoft Certified Solutions Developer: Windows Store Apps in C#