Discover Properties of Storage Items in Windows Store Apps

Preface

Sometimes it is helpful to discover some or all properties of storage items (StorageFile, StorageFolder).

These classes implement the interfaces IStorageItem and IStorageItemProperties.

IStorgeItem.GetBasicPropertiesAsync gets an object that provides access to the basic properties of an item. IStorageItemProperties.Properties gets an object that provides access to the content-related properties of an item.

To get the properties themselves, you need to call BasicProperties.RetrievePropertiesAsync respectively StorageItemContentProperties.RetrievePropertiesAsync. Both methods expect a list of property names to retrieve. But, at the time of writing this post, the docs do not give a hint on the question:

Which Properties are Available?

The complete list of possible property names can be found here.

But the list does not tell you which property is available on which storage item type. Images might have some other properties like text files or folders. Luckily, there is an undocumented way (undocumented at the time of writing) to get a list of all possible properties: Just pass an empty list. This returns a list of all properties of the current storage item both for basic and content-related properties.

Exceptions

Using the empty-list approach I noticed that there is at minimum one exception to the rule. Having a StorageFolder object of the root directory of a drive, e.g. c:\, the properties “System.ItemType” and “System.ItemTypeText” are not contained in the returned dictionary.

On the other hand, calling StorageItemContentProperties.RetrievePropertiesAsync(new string[] { "Type" }) on such a storage item, the result contains one entry with the key “System.ItemTypeText” with the value “Local Disk” (or “Network Drive”). Please notice that there is no property named “Type” contained in the list of available properties. The behavior is the same on Windows 8.1 Preview.

Discovering

Putting this together, one might think that the combination of basic and content-related properties gives the sum of all properties. Well, it does. But from what I saw during my tests, both lists contain the items. There is no difference between the basic and the content-related list. So you are free to use one of them (observed this on Windows 8.1 Preview too).

Tracing Basic Properties

To trace out all the properties using the basic interface, one might use this code:

private static async Task TraceBasicPropertiesAsync
  (
  IStorageItem storageItem
  )
{
  Debug.WriteLine(
    "{0}Tracing basic properties of storage item >{1}< / >{2}<", 
    Environment.NewLine, storageItem.Name, storageItem.Path);

  BasicProperties basicProperties 
    = await storageItem.GetBasicPropertiesAsync();

  Debug.WriteLine(String.Format(CultureInfo.InvariantCulture, 
    "DateModified {0:u} (UTC), ItemDate {1:u} (UTC), Size {2}", 
    basicProperties.DateModified, basicProperties.ItemDate, 
    basicProperties.Size));

  IDictionary<string, object> basicPropertyList 
    = await basicProperties.RetrievePropertiesAsync(new string[] { });

  foreach (KeyValuePair<string, object> property 
    in basicPropertyList.OrderBy(item => item.Key))
  {
    Debug.WriteLine("BasicProperty >{0}<: >{1}<", 
      property.Key, property.Value);
  }

  if (basicPropertyList.ContainsKey("System.Kind"))
  {
    foreach (string kind 
      in (string[]) basicPropertyList["System.Kind"])
    {
      Debug.WriteLine("BasicProperty kind >{0}<", kind);
    }
  }
}

Tracing Content-Related Properties

The code to trace all the content-related properites looks very similar:

private static async Task TraceContentRelatedPropertiesAsync
  (
  IStorageItem storageItem
  )
{
  Debug.WriteLine(
    "{0}Tracing content-related properties of storage item >{1}< / >{2}<",
    Environment.NewLine, storageItem.Name, storageItem.Path);

  // We need a different interface to access the 
  // content-related properties.
  IStorageItemProperties storageItemProperties 
    = storageItem as IStorageItemProperties;

  if (storageItemProperties == null)
  {
    Debug.WriteLine("IStorageItemProperties not implemented",
      Environment.NewLine);
    return;
  }

  IDictionary<string, object> propertyList 
    = await storageItemProperties.Properties
      .RetrievePropertiesAsync(new string[] { });

  foreach (KeyValuePair<string, object> property 
    in propertyList.OrderBy(item => item.Key))
  {
    Debug.WriteLine("Property >{0}<: >{1}<", 
      property.Key, property.Value);
  }

  if (propertyList.ContainsKey("System.Kind"))
  {
    foreach (string kind 
      in (string[]) propertyList["System.Kind"])
    {
      Debug.WriteLine("Property kind >{0}<", kind);
    }
  }

  // Handle missing properties for root directories.
  if (!propertyList.ContainsKey("System.ItemTypeText"))
  {
    IDictionary<string, object> missingList
      = await storageItemProperties.Properties
        .RetrievePropertiesAsync(
          new string[] { "System.ItemType", "System.ItemTypeText" });

    foreach (KeyValuePair<string, object> property 
      in missingList.OrderBy(item => item.Key))
    {
      Debug.WriteLine("Property >{0}<: >{1}<", 
        property.Key, property.Value);
    }
  }
}

There is an extra loop on the “System.Kind” property becaus it contains a string array.

Links

Windows Property System that can be set on Windows files