question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: TypeConverter-equivalent for class properties (attribute)

See original GitHub issue

Proposal: TypeConverter-equivalent for class properties

Summary

In WPF, it’s possible to define a TypeConverter type to manually implement conversion logic from a string to arbitrary types when parsing XAML code. This is not supported on UWP. UWP does have the [CreateFromString] attribute, but that only works for custom types. This is not a replacement for TypeConverter, as it misses one important use case: being able to implement parsing logic for types you don’t own, when used as properties in types you do own.

Example

I’m working on a rewrite for the Microsoft.Toolkit.Uwp.UI.Animations package (here), and I have a bunch of classes that would ideally expose properties of types such as Vector3 and Vector4. The XAML compiler currently does not support parsing these types automatically on custom types. But even if it did, that would not be a solution, as developers need to be able to define parsing logic themselves (we can’t just assume they’ll never have to parse some type that’s already built-in in the XAML parser).

Consider this simple example:

public sealed class TranslationAnimation
{
    public Vector3? From { get; set; }
    public Vector3? To { get; set; }
}

This will just fail to parse in XAML, and it will crash. I can’t use [CreateFromString], because I do not own Vector3. There are currently two solutions:

  1. Add a markup extension that converts string to Vector3?. This retains type safety on the class, but makes the code very verbose, as now consumers will always need to do From="{ex:Vector3Extensions Value=20,0,0}" instead of just From="20,0,0". This is too much to ask to consumers for every single usage, and that’s why I didn’t go for this solution in the Toolkit either.
  2. Introduce a generic type in the class architecture that allows specifying parsing type and parsed type, so that for types not supported by XAML, such as this one, classes can just use string as public type and then implement a custom logic. Something like this, which is untimately what I did in that PR:
public abstract class Animation<TValue, TKeyFrame>
    where TKeyFrame : unmanaged
{
    public TValue? To { get; set; }
    public TValue? From { get; set; }

    protected abstract (TKeyFrame? To, TKeyFrame? From) GetParsedValues();
}

public sealed class TranslationAnimation : Animation<string, Vector3>
{
    protected override (Vector3?, Vector3?) GetParsedValues()
    {
        return (To?.ToVector3(), From?.ToVector3());
    }
}

Consumers can now use the nice compact syntax in XAML, and classes can handle all the parsing logic. Now, this works, but it’s… Pretty terrible for a number of reasons:

  1. You’re forced to introduce extra complexity (more type parameters, extra abstract parsing methods, etc.)
  2. The actual type of values in the animation is… Wrong. This TranslationAnimation will expose To and From as string values instead of just Vector3? values as it should be. This makes it pretty bad in cases where users might have wanted to actually set a concrete Vector3 value directly, as they’ll have to round-trip to a string first.

I’m not super familiar with the various WinRT limitations that could come into play with implementing a solution here, but really any sort of solution that would allow consumers to just add an attribute over properties to indicate how to parse them would work fine. Either:

  • Add support for [TypeConverter]
  • Allow [CreateFromString] to be used as an attribute over properties (and not just type)
  • Some new attribute specifically for properties

Any of these 3 solutions or an equivalent one would work just great, really 😄

Rationale

  • Allow consumers to fill in where the built-in XAML parser doesn’t support types
  • Allow consumers to customize the XAML parsing behavior for properties
  • Reduce the code complexity to work around this limitation today

Scope

Capability Priority
Allow developers to annotate properties to supply a custom parsing method Must

API example/proposal

Here’s an example of how this could work in case [CreateFromString] support for properties was introduced:

public sealed class TranslationAnimation
{
    [CreateFromString(MethodName = "Microsoft.Toolkit.Uwp.UI.Extensions.VisualExtensions.ToVector3")]
    public Vector3? From { get; set; }

    [CreateFromString(MethodName = "Microsoft.Toolkit.Uwp.UI.Extensions.VisualExtensions.ToVector3")]
    public Vector3? To { get; set; }
}

Usage:

<TranslationAnimation From="0" To="20,0,0" />

Perfect! 🎉

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:12
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
StephenLPeterscommented, Jan 8, 2021

@ryandemopoulos seems like a cool idea

1reaction
MikeHillbergcommented, Jan 20, 2021

I like the approach of [CreateFromString] supporting the property case.

What I don’t like about type converters is that there’s no type information telling you what input types are supported or what type you’re going to get out. With CreateFromString it’s more clear (though you still don’t know the specific string syntax). It’s also nice that CreateFromString is clear as to how to get the same functionality from code as from markup (you can do the same with a TypeConverter but the code’s more cumbersome and less obvious and not typed).

Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeConverter usage for class property
I have a class EntityItemValue which has property named Value of type object , the actual type can be determined through property named...
Read more >
TypeConverterAttribute Class (System.ComponentModel)
The class you use for conversion must inherit from TypeConverter. Use the ConverterTypeName property to get the name of the class that provides...
Read more >
How to use TypeConverter that is applied to a property ...
I have more than 20 different TypeConvertes for converting between meters and millimeters, degress and radians etc. To do that I am overriding ......
Read more >
Type Converters | Design-Time Integration
The TypeDescriptor class provides information about a particular type or object, including methods, properties, events, and attributes.
Read more >
Writing Custom Attributes
Design your own custom attributes in .NET. Custom attributes are essentially classes derived directly or indirectly from System.Attribute.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found