AttachedProperty Part 2, Putting it Together

On my last post, Jason jumped right to the punchline in his comment here. He asks “if there is an easy way to have the properties value serialized out to the xaml.”

First, let’s look at what we need to do from the XAML side.

First, create a helper type with a getter and setter for the property that you want to attach.  Here we’re going to attach comments:

 public class Comment
{
    static AttachableMemberIdentifier CommentTextName = new AttachableMemberIdentifier(typeof(Comment), "CommentText");

    public static object GetCommentText(object instance)
    {
        object viewState;
        AttachablePropertyServices.TryGetProperty(instance, CommentTextName, out viewState);
        return viewState;
    }

    public static void SetCommentText(object instance, object value)
    {
        AttachablePropertyServices.SetProperty(instance, CommentTextName, value);
    }

}

Next, let’s use the AttachableMemberIdentifier and the AttachablePropertyServices to do something interesting with this:

 AttachableMemberIdentifier ami = new AttachableMemberIdentifier(typeof(Comment), "CommentText");
Dog newDog = new Dog { Age = 12, Name = "Sherlock", Noise = "Hooowl" };
AttachablePropertyServices.SetProperty(newDog, ami, "A very good dog");
string s = XamlServices.Save(newDog);
Console.WriteLine("XAML");
Console.WriteLine(s);
Dog aSecondNewDog = XamlServices.Load(new StringReader(s)) as Dog;
string outter;
AttachablePropertyServices.TryGetProperty(aSecondNewDog, ami, out outter);
Console.WriteLine("read out: {0}", outter);

Let’s see the output from this:

 XAML
<Dog
     Age="12"
     Comment.CommentText="A very good dog"
     Name="Sherlock"
     Noise="Hooowl" 
     xmlns="clr-namespace:AttachedPropertiesBlogPosting;assembly=AttachedPropertiesBlogPosting" />
read out: A very good dog

You’ll note that the value is contained in the XAML under Comment.CommentText.

Pulling it all Together

Let’s take what we did in the last post and combine it with the above stuff in order to have an attached property that writes through and is stored inside the XAML.

 AttachedProperty<string> Comment = new AttachedProperty<string>
{
    IsBrowsable = true,
    Name = "Comment",
    Getter = (mi =>
        { string temp;
          AttachablePropertyServices.TryGetProperty<string>(mi.GetCurrentValue(), ami, out temp);
          return temp;
        }),
    Setter = ( (mi,val) => AttachablePropertyServices.SetProperty(mi.GetCurrentValue(), ami, val) )

};
aps.AddProperty(Comment);
dogMi.Properties["Comment"].SetValue("I think I like that dog");
string xaml = XamlServices.Save(dogMi.GetCurrentValue());
Console.WriteLine("XAML");
Console.WriteLine(xaml);

What are we doing here, well, we basically just use the Getter and Setter to write through to the underlying instance.  You’ll note that usually, we never want to go and use GetCurrentValue(), as any changes made there are not made via the ModelItem tree which means we might miss a change notification.  However, given that the only place where we can store the XAML attached property is on the instance itself, this gives us a good way to write through.  The XAML output below shows that this works as expected:

 <Dog 
   Age="5"
   Comment.CommentText="I think I like that dog"
   Name="Sasha" 
   Noise="Snort" 
   xmlns="clr-namespace:AttachedPropertiesBlogPosting;assembly=AttachedPropertiesBlogPosting" />