locked
Trying to use file.GetBasicPropertiesAsync in a universal app

    Question

  • I'm working on a Universal app and decided since FileInformation is not available on the phone that I needed to use the less efficient "walk all the folders and files" method.

    The problem is, in Windows 8.1 simulator (not phone) when I try to get BasicProperties on a StorageFile object,  using file.GetBasicPropertiesAsync(), I get a null return.

            public async void SetFilePropertiesAsync()
            {
                this.basicProperties = await musicFile.GetBasicPropertiesAsync() ;
                this.musicProperties = await musicFile.Properties.GetMusicPropertiesAsync();
            }
    

    The same is true for the related file.Properties.GetMusicPropertiesAsync();

    The FileInformation calls work on Windows 8.1 in the simulator, but if I do that, then I'll have to have unique code for each of Windows Store and Phone.

    Is that behavior expected for Windows 8.1 simulator?

    -thanks
    -e


    -- me --

    Tuesday, May 20, 2014 5:55 AM

Answers

  • I did even more investigation, and perhaps others have the same problem, so I include a link to an important Windows Phone 8 specific page I had not found before:

    http://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn639127.aspx

    This one explains using the deep queries allow for catching all the folders or files for the known folders Music Library, and just how things work.

    A deep query is one like:

    folder.GetFoldersAsync(CommonFolderQuery.GroupByAlbum);

    Since I didn't find that page  before, I wondered for a second if it is new.  If it is, then thanks for updating the documentation with what I was originally looking for when I started trying to find the MediaLibrary equivalent for Windows Phone 8.x,

    My code isn't perfect, but I'll include it here for anyone who may have the same or similar problem.

    Using this, it only takes a second or two to get my albums listed on the phone, so not bad.  I could do more async work and using a virtual scrolling list, etc, in order to make things more responsive, but this was just an initial test.

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Windows.Storage;
    #if WINDOWS_APP
    using Windows.Storage.BulkAccess;
    #endif
    using Windows.Storage.FileProperties;
    using Windows.Storage.Search;
    
    namespace HubApp1
    {
        public class MusicFolderData
        {
            public StorageFolder musicFolder { get; set; }
            public MusicProperties musicProperties { get; set; }
            public BasicProperties basicProperties { get; set; }
            public StorageItemThumbnail folderThumbnail { get; set; }
            public ObservableCollection<MusicFileData> musicFiles { get; set; }
    
            public MusicFolderData()
            {
            }
    
            public void PopulateFolderData( StorageFolder folder )
            {
    #if WINDOWS_PHONE_APP
                this.musicFolder = folder ;
    #endif
                this.SetFolderPropertiesAsync() ;
                this.musicFiles = new ObservableCollection<MusicFileData>();
            }
    
            public MusicFolderData( StorageFolder folder )
            {
                PopulateFolderData( folder );
            }
    
    #if WINDOWS_APP
            public FolderInformation fInfo { get; set; }
    
            private async void SetFolderPropertiesAsync()
            {
                this.basicProperties = await fInfo.GetBasicPropertiesAsync();
                this.musicProperties = fInfo.MusicProperties;
    
                this.folderThumbnail = await fInfo.GetThumbnailAsync(ThumbnailMode.MusicView, 190);
            }
    #else
            private async void SetFolderPropertiesAsync()
            {
                MusicData.IncrTotalObject();
    
                try
                {
                    this.basicProperties = await this.musicFolder.GetBasicPropertiesAsync();
                    this.musicProperties = await this.musicFolder.Properties.GetMusicPropertiesAsync();
    
                    this.folderThumbnail = await this.musicFolder.GetThumbnailAsync(ThumbnailMode.MusicView, 190);
                }
                catch
                {
                    MusicData.IncrTotalException();
                    // do nothing if we get an exception, which we seem to sometimes
                }
            }
    #endif
            public string AlbumTitle
            {
                get
                {
                    if (this.musicProperties.Album.Length > 0)
                    {
                        return this.musicProperties.Album;
                    }
                    else
                    {
                        return this.musicProperties.Title;
                    }
                }
                    
            }
    
            public string AlbumArtist
            {
                get
                {
                    if (this.musicProperties.AlbumArtist.Length > 0)
                    {
                        return this.musicProperties.AlbumArtist;
                    }
                    else
                    {
                        return this.musicProperties.Artist;
                    }
                }
            }
    
            public void AddMusicFile( StorageFile file )
            {
                var mFI = new MusicFileData( file ) ;
                this.musicFiles.Add( mFI );
            }
        }
    
        public class MusicFileData
        {
            public StorageFile musicFile { get; set; }
    
            public MusicProperties musicProperties { get; set; }
            public BasicProperties basicProperties { get; set; }
    
            public MusicFileData()
            {
            }
    
            public MusicFileData( StorageFile file )
            {
    #if WINDOWS_PHONE_APP
                this.musicFile = file ;
    #endif
                this.SetFilePropertiesAsync();
    
                return;
            }
    
            public void PopulateFileData()
            {
                SetFilePropertiesAsync();
            }
    
    #if WINDOWS_APP
            public FileInformation fInfo {get; set; }
    
            public async void SetFilePropertiesAsync()
            {
                this.basicProperties = await fInfo.GetBasicPropertiesAsync() ;
                this.musicProperties = fInfo.MusicProperties;
            }
    #else
            public async void SetFilePropertiesAsync()
            {
                this.basicProperties = await musicFile.GetBasicPropertiesAsync() ;
                this.musicProperties = await musicFile.Properties.GetMusicPropertiesAsync();
            }
    #endif
        }
    
        public class MusicData
        {
            public ObservableCollection<MusicFolderData> musicFolders { get; set; }
            public static int total_object = 0;
            public static int total_folder = 0;
            public static int total_exceptions = 0;
    
            public MusicData()
            {
                this.musicFolders = new ObservableCollection<MusicFolderData>();
    
                this.PopulateFolderInfoAsync(KnownFolders.MusicLibrary);
          //      this.PopulateArtistsAsync();
          //      this.PopulateTracksAsync();
    
                return;
            }
    
            public static void IncrTotalObject()
            {
                total_object++ ;
            }
    
            public static void IncrTotalException()
            {
                total_exceptions++;
            }
    
    #if WINDOWS_APP
            async void PopulateFolderInfoAsync(StorageFolder top_folder = null)
            {
                StorageFolderQueryResult query = top_folder.CreateFolderQuery(
                  CommonFolderQuery.GroupByAlbum);
    
                FileInformationFactory factory = new FileInformationFactory(query,
                  Windows.Storage.FileProperties.ThumbnailMode.MusicView,
                  250,
                  Windows.Storage.FileProperties.ThumbnailOptions.ResizeThumbnail);
    
                IReadOnlyList<FolderInformation> folderList = await factory.GetFoldersAsync();
    
                total_folder = folderList.Count;
    
                foreach (var folder in folderList)
                {
                    var mD = new MusicFolderData();
                    mD.fInfo = folder;
                    mD.PopulateFolderData(null);
    
                    this.musicFolders.Add(mD);
    
    #if DO_FILES
                    // do something more with this filter string later
                    QueryOptions options = new QueryOptions(CommonFileQuery.OrderByMusicProperties, new string[] { ".mp3" });
    
                    StorageFileQueryResult trackQuery = folder.CreateFileQueryWithOptions(options);
    
                    FileInformationFactory trackFactory = new FileInformationFactory(trackQuery, ThumbnailMode.MusicView);
    
                    IReadOnlyList<FileInformation> tracks = await trackFactory.GetFilesAsync();
    
                    foreach (var track in tracks)
                    {
                        var mF = new MusicFileData();
                        mF.fInfo = track;
                        mF.PopulateFileData();
                        this.total_object++;
                    }
    #endif
                }
    
                return; // done
            }
    #else
            async void PopulateFolderInfoAsync( StorageFolder top_folder = null )
            {
                IReadOnlyList<StorageFolder> folderList = await top_folder.GetFoldersAsync(CommonFolderQuery.GroupByAlbum);
    
                total_folder += folderList.Count;
    
                foreach (var folder in folderList)
                {
                    var mD = new MusicFolderData(folder);
                    this.musicFolders.Add(mD);
    
    #if DO_RECRUSE
                    PopulateFolderInfoAsync( folder );
    #endif
    #if DO_FILES
                    IReadOnlyList<StorageFile> fileList = await folder.GetFilesAsync(CommonFileQuery.OrderByName);
                    foreach (var file in fileList)
                    {
                        mD.AddMusicFile(file);
                        this.total_object++;
                    }
    #endif
                }
            }
    #endif
        }
    }

    I did find also that the use of the MusicProperties.Album and MusicProperties.Title objects are different under Windows 8.1 and Windows Phone 8.1, so I hid that complexity in the get method.  The rest I did with conditional compilation.

    Notice the try/catch around the musicProperties being populated.  That one appears to happen a lot, but it also appears to be because the MusicProperties are not set on the folder, so it isn't an album anyway.  As another post suggested, I just ignore the exception, but just for jokes, I keep count of them.

    the very rough class allows for use in a Universal app in a basic way, to be extended by our brilliant community here.

    My XAML uses simple DataBinding to get to the MusicData class and display the data.  It is a really hacked-up HubApp, so I didn't include it here, as it would need a lot of cleanup.

    -enjoy
    -e


    -- me --



    • Marked as answer by Chief Scientist Sunday, June 01, 2014 8:38 PM
    • Edited by Chief Scientist Sunday, June 01, 2014 8:52 PM adding details and other gotchas
    Sunday, June 01, 2014 8:38 PM

All replies

  • I can't reproduce this. I get both the basic and music properties with your code snippet on my Windows 8.1 computer both running locally and in the simulator.

    Does it fail for you on only the one machine or on several?

    --Rob

    Tuesday, May 20, 2014 10:48 PM
    Owner
  • I certainly appreciate the help, Rob. I have only tried on one machine, which is an i7 desktop. The music is on an external USB disk. the same code worked with FileInformation and FolderInformation objects. I will investigate further.


    -- me --

    Tuesday, May 20, 2014 10:55 PM
  • I was a bit incomplete with my explanation here.

    1) The problem I'm really seeing is the "dreaded" "function evaluation timed out" in the debugger on both basicProperties and musicProperties.

    2) Also, here's the full code:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Windows.Storage;
    #if WINDOWS_APP
    using Windows.Storage.BulkAccess;
    #endif
    using Windows.Storage.FileProperties;
    using Windows.Storage.Search;
    
    namespace HubApp1
    {
        public class MusicFolderData
        {
            public StorageFolder musicFolder { get; set; }
            public MusicProperties musicProperties { get; set; }
            public BasicProperties basicProperties { get; set; }
            public StorageItemThumbnail folderThumbnail { get; set; }
            public ObservableCollection<MusicFileData> musicFiles { get; set; }
    
    
            public MusicFolderData( StorageFolder folder )
            {
                this.musicFolder = folder ;
                this.SetFolderPropertiesAsync() ;
                this.musicFiles = new ObservableCollection<MusicFileData>();
            }
    
            private async void SetFolderPropertiesAsync()
            {
                this.basicProperties = await this.musicFolder.GetBasicPropertiesAsync() ;
                this.musicProperties = await this.musicFolder.Properties.GetMusicPropertiesAsync();
    
                this.folderThumbnail = await this.musicFolder.GetThumbnailAsync(ThumbnailMode.MusicView, 190);
    
                return;
            }
    
            public string AlbumTitle
            {
                get { return this.musicProperties.Album; }
            }
    
            public string AlbumArtist
            {
                get { return this.musicProperties.Artist; }
            }
    
            public void AddMusicFile( StorageFile file )
            {
                var mFI = new MusicFileData( file ) ;
                this.musicFiles.Add( mFI );
            }
        }
    
        public class MusicFileData
        {
            public StorageFile musicFile { get; set; }
    
            public MusicProperties musicProperties { get; set; }
            public BasicProperties basicProperties { get; set; }
    
            public MusicFileData( StorageFile file )
            {
                this.musicFile = file ;
                this.SetFilePropertiesAsync();
    
                return;
            }
    
            public async void SetFilePropertiesAsync()
            {
                this.basicProperties = await musicFile.GetBasicPropertiesAsync() ;
                this.musicProperties = await musicFile.Properties.GetMusicPropertiesAsync();
            }
        }
    
        public class MusicData
        {
            public ObservableCollection<MusicFolderData> musicFolders { get; set; }
            public int total_object = 0;
            public int total_folder = 0;
    
            public MusicData()
            {
                this.musicFolders = new ObservableCollection<MusicFolderData>();
    
                this.PopulateFolderInfoAsync();
          //      this.PopulateArtistsAsync();
          //      this.PopulateTracksAsync();
    
                return;
            }
    
            async void PopulateFolderInfoAsync()
            {
                IReadOnlyList<StorageFolder> folderList = await KnownFolders.MusicLibrary.GetFoldersAsync();
    
                this.total_folder = folderList.Count;
    
                foreach (var folder in folderList)
                {
                    var mD = new MusicFolderData(folder);
                    this.musicFolders.Add(mD);
    
                    /*
                    IReadOnlyList<StorageFile> fileList = await folder.GetFilesAsync(CommonFileQuery.OrderByName);
                    foreach (var file in fileList)
                    {
                        mD.AddMusicFile(file);
                        this.total_object++;
                    }
                     */
                }
            }
        }
    }
    

    Does the larger codeset help you to see my problem, or on your machine does it all work?

    I appreciate your time.

    -e


    -- me --

    Wednesday, May 21, 2014 2:13 AM
  • I did verify things worked okay with FolderInformation with windows 8.  I am still having a lot of trouble with function eval timeouts in the debugger.  Any help you can offer would be appreciated.

    -cheers
    -e


    -- me --

    Wednesday, May 21, 2014 3:54 AM
  • Do you have problems with this outside of the debugger?

    I believe the function eval timeout you refer to is function of the debugger and not something that will affect the app outside of the debugger. It is a system to prevent the debugger from hanging on circular watches and such.

    It may be that trying to read from the USB drive is slow enough that the debugger gives up.

    --Rob

    Friday, May 23, 2014 2:30 AM
    Owner
  • Hi Rob,

    Just getting back to this.  NO fault of yours, of course, but there were delays.

    It is good thing this isn't my only job.

    At any rate, I now have success calling the GetMusicPropertiesAsync() method, but never get much back.  The properties all seem to be empty strings.

    I've seen this in both the debugger and on the phone. 

    I have a listview of the entries returning from the call:

    IReadOnlyList<StorageFolder> folderList = await KnownFolders.MusicLibrary.GetFoldersAsync();

    And there are 4 entries.

    Unfortunately, though this returns valid DateTimes

               this.basicProperties = await musicFile.GetBasicPropertiesAsync() ;
     
    The GetMusicPropertiesAsync() call returns nothing useful:

    -  musicProperties {Windows.Storage.FileProperties.MusicProperties} Windows.Storage.FileProperties.MusicProperties
      Album "" string
      AlbumArtist "" string
      Artist "" string
      Bitrate 0 uint
    +  Composers COM Object System.Collections.Generic.IList<string> {System.__ComObject}
    +  Conductors COM Object System.Collections.Generic.IList<string> {System.__ComObject}

    I did realize I needed to recursively visit the folders, so I added that to my code, but still not getting any useful music properties back.

    I'm not sure what to try next.

    BTW, this is on a real device (1520) with the latest WP 8.1 dev preview.   I did this because the device has music on it, but the emulator does not.

    -thanks
    -e


    -- me --

    Sunday, June 01, 2014 12:36 AM
  • I did even more investigation, and perhaps others have the same problem, so I include a link to an important Windows Phone 8 specific page I had not found before:

    http://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn639127.aspx

    This one explains using the deep queries allow for catching all the folders or files for the known folders Music Library, and just how things work.

    A deep query is one like:

    folder.GetFoldersAsync(CommonFolderQuery.GroupByAlbum);

    Since I didn't find that page  before, I wondered for a second if it is new.  If it is, then thanks for updating the documentation with what I was originally looking for when I started trying to find the MediaLibrary equivalent for Windows Phone 8.x,

    My code isn't perfect, but I'll include it here for anyone who may have the same or similar problem.

    Using this, it only takes a second or two to get my albums listed on the phone, so not bad.  I could do more async work and using a virtual scrolling list, etc, in order to make things more responsive, but this was just an initial test.

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Windows.Storage;
    #if WINDOWS_APP
    using Windows.Storage.BulkAccess;
    #endif
    using Windows.Storage.FileProperties;
    using Windows.Storage.Search;
    
    namespace HubApp1
    {
        public class MusicFolderData
        {
            public StorageFolder musicFolder { get; set; }
            public MusicProperties musicProperties { get; set; }
            public BasicProperties basicProperties { get; set; }
            public StorageItemThumbnail folderThumbnail { get; set; }
            public ObservableCollection<MusicFileData> musicFiles { get; set; }
    
            public MusicFolderData()
            {
            }
    
            public void PopulateFolderData( StorageFolder folder )
            {
    #if WINDOWS_PHONE_APP
                this.musicFolder = folder ;
    #endif
                this.SetFolderPropertiesAsync() ;
                this.musicFiles = new ObservableCollection<MusicFileData>();
            }
    
            public MusicFolderData( StorageFolder folder )
            {
                PopulateFolderData( folder );
            }
    
    #if WINDOWS_APP
            public FolderInformation fInfo { get; set; }
    
            private async void SetFolderPropertiesAsync()
            {
                this.basicProperties = await fInfo.GetBasicPropertiesAsync();
                this.musicProperties = fInfo.MusicProperties;
    
                this.folderThumbnail = await fInfo.GetThumbnailAsync(ThumbnailMode.MusicView, 190);
            }
    #else
            private async void SetFolderPropertiesAsync()
            {
                MusicData.IncrTotalObject();
    
                try
                {
                    this.basicProperties = await this.musicFolder.GetBasicPropertiesAsync();
                    this.musicProperties = await this.musicFolder.Properties.GetMusicPropertiesAsync();
    
                    this.folderThumbnail = await this.musicFolder.GetThumbnailAsync(ThumbnailMode.MusicView, 190);
                }
                catch
                {
                    MusicData.IncrTotalException();
                    // do nothing if we get an exception, which we seem to sometimes
                }
            }
    #endif
            public string AlbumTitle
            {
                get
                {
                    if (this.musicProperties.Album.Length > 0)
                    {
                        return this.musicProperties.Album;
                    }
                    else
                    {
                        return this.musicProperties.Title;
                    }
                }
                    
            }
    
            public string AlbumArtist
            {
                get
                {
                    if (this.musicProperties.AlbumArtist.Length > 0)
                    {
                        return this.musicProperties.AlbumArtist;
                    }
                    else
                    {
                        return this.musicProperties.Artist;
                    }
                }
            }
    
            public void AddMusicFile( StorageFile file )
            {
                var mFI = new MusicFileData( file ) ;
                this.musicFiles.Add( mFI );
            }
        }
    
        public class MusicFileData
        {
            public StorageFile musicFile { get; set; }
    
            public MusicProperties musicProperties { get; set; }
            public BasicProperties basicProperties { get; set; }
    
            public MusicFileData()
            {
            }
    
            public MusicFileData( StorageFile file )
            {
    #if WINDOWS_PHONE_APP
                this.musicFile = file ;
    #endif
                this.SetFilePropertiesAsync();
    
                return;
            }
    
            public void PopulateFileData()
            {
                SetFilePropertiesAsync();
            }
    
    #if WINDOWS_APP
            public FileInformation fInfo {get; set; }
    
            public async void SetFilePropertiesAsync()
            {
                this.basicProperties = await fInfo.GetBasicPropertiesAsync() ;
                this.musicProperties = fInfo.MusicProperties;
            }
    #else
            public async void SetFilePropertiesAsync()
            {
                this.basicProperties = await musicFile.GetBasicPropertiesAsync() ;
                this.musicProperties = await musicFile.Properties.GetMusicPropertiesAsync();
            }
    #endif
        }
    
        public class MusicData
        {
            public ObservableCollection<MusicFolderData> musicFolders { get; set; }
            public static int total_object = 0;
            public static int total_folder = 0;
            public static int total_exceptions = 0;
    
            public MusicData()
            {
                this.musicFolders = new ObservableCollection<MusicFolderData>();
    
                this.PopulateFolderInfoAsync(KnownFolders.MusicLibrary);
          //      this.PopulateArtistsAsync();
          //      this.PopulateTracksAsync();
    
                return;
            }
    
            public static void IncrTotalObject()
            {
                total_object++ ;
            }
    
            public static void IncrTotalException()
            {
                total_exceptions++;
            }
    
    #if WINDOWS_APP
            async void PopulateFolderInfoAsync(StorageFolder top_folder = null)
            {
                StorageFolderQueryResult query = top_folder.CreateFolderQuery(
                  CommonFolderQuery.GroupByAlbum);
    
                FileInformationFactory factory = new FileInformationFactory(query,
                  Windows.Storage.FileProperties.ThumbnailMode.MusicView,
                  250,
                  Windows.Storage.FileProperties.ThumbnailOptions.ResizeThumbnail);
    
                IReadOnlyList<FolderInformation> folderList = await factory.GetFoldersAsync();
    
                total_folder = folderList.Count;
    
                foreach (var folder in folderList)
                {
                    var mD = new MusicFolderData();
                    mD.fInfo = folder;
                    mD.PopulateFolderData(null);
    
                    this.musicFolders.Add(mD);
    
    #if DO_FILES
                    // do something more with this filter string later
                    QueryOptions options = new QueryOptions(CommonFileQuery.OrderByMusicProperties, new string[] { ".mp3" });
    
                    StorageFileQueryResult trackQuery = folder.CreateFileQueryWithOptions(options);
    
                    FileInformationFactory trackFactory = new FileInformationFactory(trackQuery, ThumbnailMode.MusicView);
    
                    IReadOnlyList<FileInformation> tracks = await trackFactory.GetFilesAsync();
    
                    foreach (var track in tracks)
                    {
                        var mF = new MusicFileData();
                        mF.fInfo = track;
                        mF.PopulateFileData();
                        this.total_object++;
                    }
    #endif
                }
    
                return; // done
            }
    #else
            async void PopulateFolderInfoAsync( StorageFolder top_folder = null )
            {
                IReadOnlyList<StorageFolder> folderList = await top_folder.GetFoldersAsync(CommonFolderQuery.GroupByAlbum);
    
                total_folder += folderList.Count;
    
                foreach (var folder in folderList)
                {
                    var mD = new MusicFolderData(folder);
                    this.musicFolders.Add(mD);
    
    #if DO_RECRUSE
                    PopulateFolderInfoAsync( folder );
    #endif
    #if DO_FILES
                    IReadOnlyList<StorageFile> fileList = await folder.GetFilesAsync(CommonFileQuery.OrderByName);
                    foreach (var file in fileList)
                    {
                        mD.AddMusicFile(file);
                        this.total_object++;
                    }
    #endif
                }
            }
    #endif
        }
    }

    I did find also that the use of the MusicProperties.Album and MusicProperties.Title objects are different under Windows 8.1 and Windows Phone 8.1, so I hid that complexity in the get method.  The rest I did with conditional compilation.

    Notice the try/catch around the musicProperties being populated.  That one appears to happen a lot, but it also appears to be because the MusicProperties are not set on the folder, so it isn't an album anyway.  As another post suggested, I just ignore the exception, but just for jokes, I keep count of them.

    the very rough class allows for use in a Universal app in a basic way, to be extended by our brilliant community here.

    My XAML uses simple DataBinding to get to the MusicData class and display the data.  It is a really hacked-up HubApp, so I didn't include it here, as it would need a lot of cleanup.

    -enjoy
    -e


    -- me --



    • Marked as answer by Chief Scientist Sunday, June 01, 2014 8:38 PM
    • Edited by Chief Scientist Sunday, June 01, 2014 8:52 PM adding details and other gotchas
    Sunday, June 01, 2014 8:38 PM