Open Sergio0694 opened 3 years ago
@ryandemopoulos seems like a cool idea
Optionally one could think about separating the source type information from the MethodName
property, to make such references to break less likely on code refactorings:
public sealed class TranslationAnimation
{
[CreateFromString(SourceType = typeof(VisualExtensions), MethodName = nameof(VisualExtensions.ToVector3))]
public Vector3? From { get; set; }
[CreateFromString(SourceType = typeof(VisualExtensions), MethodName = nameof(VisualExtensions.ToVector3))]
public Vector3? To { get; set; }
}
@MichaeIDietrich That certainly would be a welcome addition, though since that change would apply to the [CreateFromString]
attribute as it already works today (as in, that would work when used normally over custom types too), I think that should go in a differeent proposal, to keep this one as small scoped as possible, so that it's easier to work on for the team π
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).
Hey @MikeHillberg, figured I'd post a small update with some more info about our specific use case.
My primary use for this feature would be to use it to finally fix the typing system in our animation types in the Windows Community Toolkit, specifically given that this would be a breaking change I could see us adopting such a feature in a new major release only targeting WinUI 3 (as this change doesn't seem likely to ever be backported to UWP anyway). I've added a summary of our current animation architecture in the first post of this issue, including its many drawbacks (multiple type parameters, "fake" strong typing, etc.). If support for [CreateFromString]
was extended to properties like you mentioned, I reckon I would be able to change:
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());
}
}
Into:
public abstract class Animation<T>
where T : unmanaged
{
public abstract T? To { get; set; }
public abstract T? From { get; set; }
}
public sealed class TranslationAnimation : Animation<Vector3>
{
[CreateFromString(MethodName = "Microsoft.Toolkit.Uwp.UI.Extensions.VisualExtensions.ToVector3")]
public override Vector3? To { get; set; }
[CreateFromString(MethodName = "Microsoft.Toolkit.Uwp.UI.Extensions.VisualExtensions.ToVector3")]
public override Vector3? From { get; set; }
}
Which would be such a massive improvement and what I wish I could have done from the start π
Not only the types themselves would be way less verbose due to not having to carry out that super clunky secondary type parameter (that's really only needed to make the code compile) and having to invoke a parsing method every time, but also it would make it much easier for developers to immediately understand what types they're working with, and also to make their life easier if they wanted to set some of these properties directly from either code behind or some other method, as they'd be able to just stick to concrete types instead of having to pass string
instances around (hence also making code easier to maintain).
I understand there's lots of work going on with WinUI 3, but would love to know if implementing this would be complex or instead doable with relatively no big complications, and if you could see this making its way into a future WinUI 3 preview. Thanks! π
FYI @michael-hawker
Was just hitting this again too for shadows in the Toolkit. Since Vector3
itself is pretty prevalent in the framework, it'd be nice if there was just a built-in type converter to it from string so it can be used easily as a custom dependency property. I think this would help alleviate the concern raised in #2130 as well. It'd probably be an easier short-term win. Should a new issue be opened for that specific ask for Vector2/3
?
@RealTommyKlein FYI
In the cases where we're parsing static strings (vs. using binding); it'd be nice if we could have an option to pre-compute these at compile time vs. runtime too?
Bumping, though think this is a feature request, based on https://github.com/microsoft/microsoft-ui-xaml/discussions/8638
Proposal: TypeConverter-equivalent for class properties
Summary
In WPF, it's possible to define a
TypeConverter
type to manually implement conversion logic from astring
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 forTypeConverter
, 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 asVector3
andVector4
. 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:
This will just fail to parse in XAML, and it will crash. I can't use
[CreateFromString]
, because I do not ownVector3
. There are currently two solutions:1) Add a markup extension that converts
string
toVector3?
. This retains type safety on the class, but makes the code very verbose, as now consumers will always need to doFrom="{ex:Vector3Extensions Value=20,0,0}"
instead of justFrom="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 usestring
as public type and then implement a custom logic. Something like this, which is untimately what I did in that PR: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 exposeTo
andFrom
asstring
values instead of justVector3?
values as it should be. This makes it pretty bad in cases where users might have wanted to actually set a concreteVector3
value directly, as they'll have to round-trip to astring
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:
[TypeConverter]
[CreateFromString]
to be used as an attribute over properties (and not just type)Any of these 3 solutions or an equivalent one would work just great, really π
Rationale
Scope
API example/proposal
Here's an example of how this could work in case
[CreateFromString]
support for properties was introduced:Usage:
Perfect! π