Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Make styled property storage typed #3255
What does the pull request do?
Previously, when a value was set on a styled property, that property was boxed and added to the
In addition, the
Because the get/set/bind/clear methods are now typed on the value
Bindings which produce an
Note that the
Not addressed in this PR
Previously all values set via
This meant that style setters with needed to create a binding with a single value, otherwise the setter value would be lost when e.g. a setter with
This PR changes that behavior:
Avalonia properties now take a separate validation and coercion callback the same as WPF. The validation callback cannot be overridden, though the coercion callback can.
Depends on #3287
Glanced over most of your changes. I think it would be good to figure out if we can address
It will, yes. Is this a problem for you? We may need to design a replacement before we commit this change. As I mentioned, the current way coercion works slows down every single property set (including values from bindings), so it'd probably have a different API/semantics.
Yes, I’m using it for data consistency. It seems to me that it should be pretty easy to optimize the case where a property doesn’t use validation on any type by having a flag on the property that specifies whether any of its metadata has a validation function.
Since this is a breaking API change anyway: did you consider moving the static registration methods to their respective subclass? I think it's a bit cleaner to write:
StyledProperty<double> FooProperty = StyledProperty.Register<...>(...); DirectProperty<double> BarProperty = DirectProperty.Register<...>(...);
We could move them and if necessary keep the existing deprecated methods, but this should be done in a separate PR. However, I'm not completely sure that it's a change worth making at this point, when everyone's code is using the existing methods...
@mstr2 regarding coercion/validation, any thoughts on the current API as compared to the WPF/UWP API where validation is a "static" callback and only coercion receives a reference to the control?
Not sure whether to change our API to match WPF/UWP or not.
Edit: UWP doesn't have validation/coercion; I was mistaken.
From a very high-level perspective, it is my understanding that validation and coercion in WPF address two slightly different things.
Class-level validation is used to enforce that all valid objects be a class (as in set theory). More precisely, all valid objects share a common property, and an object that does not have that property can never be a valid object.
Instance-level coercion, on the other hand, is a constrained range of valid objects. This range can depend on many things and might change at any time.
While it might be elegant in theory, actual production code will often not make that distinction in practice. I understand that Avalonia is currently using a simpler approach, where the distinction between these two aspects is done by throwing an exception (object does not have a required property) or returning a coerced version of the object (object is valid, but out of range).
All other things being equal, I will always prefer the WPF behavior for the simple reason that matching this behavior will mean that, when faced with a coding problem, someone looking up solutions on the internet will find it more likely that WPF solutions will work in Avalonia.
For typed bindings, we'll have an `AvaloniaPropertyChangedEventArgs<T>` where `T` is the same as the type of the `AvaloniaPropertyObservable`. For non-typed bindings we'll have `object` as `T` so use the non-typed `AvaloniaProperty`.