XAML in .Net 4.0: Attached Properties, IAttachedPropertyStore and AttachablePropertyServices

XAML in .Net 4.0: Attached Properties, IAttachedPropertyStore and AttachablePropertyServices 

new dot net logo

Note: This post is based on Visual Studio 2010 Beta 1 which is the latest version available in the time of writing this post, so by the time this technology ships, there are probably things that will be slight different.

In a previous post I’ve talked about XAML Serialization and Deserialization using XamlServices in .Net Framework 4.0. In this post I’ll add to my data classes support for Attached Properties, so that they will be extensible during serialization.

Implement System.Xaml.IAttachedPropertyStore interface

This interface should be implemented by classes that can store attached properties.

public interface IAttachedPropertyStore

{

  int PropertyCount { get; }

  void CopyPropertiesTo(KeyValuePair<AttachableMemberIdentifier, object>[] array,
                        int index);

  bool RemoveProperty(AttachableMemberIdentifier mi);

  void SetProperty(AttachableMemberIdentifier mi, object value);

  bool TryGetProperty(AttachableMemberIdentifier mi, out object value);

}

The simplest way of implementing it, is using a Dictionary<AttachableMemberIdentifier, object> that holds the attached properties. For example, the Book class from the previous post that now implements IAttachedPropertyStore:

[RuntimeNameProperty("Name")]

[ContentProperty("Related")]

public class Book : IAttachedPropertyStore

{

  public int ISBN { get; set; }

  public string Name { get; set; }

 

  private IList<Book> related = new List<Book>();

  public IList<Book> Related { get { return this.related; } }

 

  #region IAttachedPropertyStore Members

  IDictionary<AttachableMemberIdentifier, object> attachedProperties =
new Dictionary<AttachableMemberIdentifier, object>();

  public void CopyPropertiesTo(KeyValuePair<AttachableMemberIdentifier, object>[] array,

                               int index)

  {

    attachedProperties.CopyTo(array, index);

  }

  public int PropertyCount

  {

    get { return attachedProperties.Count; }

  }

  public bool RemoveProperty(AttachableMemberIdentifier member)

  {

    return attachedProperties.Remove(member);

  }

  public void SetProperty(AttachableMemberIdentifier member, object value)

  {

    attachedProperties[member] = value;

  }

  public bool TryGetProperty(AttachableMemberIdentifier member, out object value)

  {

    return attachedProperties.TryGetValue(member, out value);

  }

  #endregion

}

Use AttachablePropertyServices  to Attach Properties to Stores

After adding support for Attached Properties to our object we can attach additional properties to it. This can be done directly with System.Xaml.AttachablePropertyServices class, but usually, we would prefer creating a class that provides strongly typed methods for those kinds of operations. For example, if we want to add more metadata to the book, such as an indication whether it is in stock or not we can create a class like this:

public class StockInfo

{

  public bool InStock { get; set; }

  public int Quantity { get; set; }

}

In order to store and retrieve the data from a class that implements IAttachedPropertyStore we can add the following static methods to the StockInfo class:

public class StockInfo

{

  public bool InStock { get; set; }

  public int Quantity { get; set; }

 

  public static StockInfo GetStockInfo(Book book)

  {

    StockInfo stockInfo = null;

    AttachablePropertyServices.TryGetProperty<StockInfo>(

      book,

      new AttachableMemberIdentifier(typeof(StockInfo), "StockInfo"),

      out stockInfo);

    return stockInfo;

  }

  public static void SetStockInfo(Book book, StockInfo stockInfo)

  {

    AttachablePropertyServices.SetProperty(

      book,

      new AttachableMemberIdentifier(typeof(StockInfo), "StockInfo"),

      stockInfo);

  }

}

Now, we can attach and retrieve the additional data from the instance:

Book book1 = new Book { Name = "First", ISBN = 123 };

StockInfo.SetStockInfo(book1, new StockInfo { InStock = true, Quantity = 27 });

StockInfo info = StockInfo.GetStockInfo(book1);

If we decided to serialize the instance with the attached properties assigned to it, we would get a serialized content like this:

<Book ISBN="123" Name="First" xmlns="clr-namespace:XamlSamples;assembly=XamlSamples">

  <StockInfo.StockInfo>

    <StockInfo InStock="True" Quantity="27" />

  </StockInfo.StockInfo>

</Book>

Summary

In this post I extended my data class (Book) with additional properties using the Attached Properties support in Xaml: Implementing the IAttachedPropertyStore interface by the data class and setting and getting the values using AttachablePropertyServices.