Implementing a type converter in UWP XAML
| CommentsVerbose XAML, we all love it right? What?! You don’t like writing massive amounts of angle brackets to get to define certain properties? I mean who doesn’t love something like this:
<MapControl> <MapControl.Center> <Location> <Location.Latitude>47.669444</Location.Latitude> <Location.Longitude>-122.123889</Location.Longitude> </Location> </MapControl.Center> </MapControl>
What’s not to love there? Oh I suppose you prefer something like this?
<MapControl Center="47.669444,-122.123889" />
In the XAML dialect this is what we refer to as a ‘type converter’ or more affectionately at times ‘string to thing’ as the declarative markup is just a string representation of some structure. In WPF and Silverlight this was implemented through requiring to use the System.ComponentModel.TypeConverter class model where you would attribute your class with a pointer to an implementation of TypeConverter that would override the common things you need, most of the time ConvertFrom capabilities.
In UWP where we currently could not rely on the exact same implementation of System.ComponentModel.TypeConverter as it is not a part of the API exposure to UWP apps at this time as well as being a .NET concept which wouldn’t be available to other WinRT developers. In looking at ways to achieve the same primary scenario, we can now look at the Creator’s Update to deliver the functionality for us. In the markup compiler for Creator’s Update we now leverage the metadata CreateFromString attribute in WinRT to generate the correct metdata to do the conversion. The responsibility lies in the owner of the class (looking at you ISVs as you update) to add this metadata capabilities.
NOTE: To enable this capability, the consuming app must currently have minimum target to the Creator’s Update.
Let’s use an example following my pseudo map control I used above. Here is my class definition for my MyMap control
using Windows.UI.Xaml.Controls; namespace CustomControlWithType { public class MyMap : Control { public MyMap() { this.DefaultStyleKey = typeof(MyMap); } public string MapTitle { get; set; } public Location CenterPoint { get; set; } } }
Notice it has a Location type. Here’s the definition of that type:
using System; namespace CustomControlWithType { public class Location { public double Latitude { get; set; } public double Longitude { get; set; } public double Altitude { get; set; } } }
Now without a type converter I can’t use the ‘string to thing’ concept in markup…I would have to use verbose markup. Let’s change that and add an attribute to my Location class, and implement the conversion function:
using System; namespace CustomControlWithType { [Windows.Foundation.Metadata.CreateFromString(MethodName = "CustomControlWithType.Location.ConvertToLatLong")] public class Location { public double Latitude { get; set; } public double Longitude { get; set; } public double Altitude { get; set; } public static Location ConvertToLatLong(string rawString) { string[] coords = rawString.Split(','); var position = new Location(); position.Latitude = Convert.ToDouble(coords[0]); position.Longitude = Convert.ToDouble(coords[1]); if (coords.Length > 2) { position.Altitude = Convert.ToDouble(coords[2]); } return position; } } }
As you can see in the highlighted lines, I added two things. First I added an attribute to my class to let it know that I have a CreateFromString method and then provided the fully qualified name to that method. The second obvious thing is to implement that method. It has to be a public static method and you can see my simple example here.
Now when using the MyMap control I can specify the simpler markup:
And the result would be converted and my control that binds to those values in it’s template are able to see them just fine
Yes, my control is quite lame but just meant to illustrate the point. The control binds to the CenterPoint.Latitude|Longitude|Altitude properties of the type.
If you are in this scenario of providing APIs that are used in UI markup for UWP apps, try this out and see if it adds delighters for your customers. I’ve uploaded the full sample of this code to my GitHub in type-converter-sample if you want to see it in full. Hope this helps!
Please enjoy some of these other recent posts...
Comments