New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's the philosophy behind the changes of XAML Composition Interop Behavior? #145

Closed
JuniperPhoton opened this Issue Aug 16, 2016 · 12 comments

Comments

Projects
None yet
7 participants
@JuniperPhoton

JuniperPhoton commented Aug 16, 2016

As always, we hope to animation the UIElement, or Visual's offset relatively, which means that I don't care where it is in its parent. For example, while I want to move the border's offset.x by value of 100, I can achieve this by:

  • Use StoryBoard and DoubleAnimation to animate the TranslateTransform.X of the border;
  • Use Composition API and simple change the offset.x of border visual like this: animation.InsertKeyFrame(1.0f, 100f);

To illustrate this:

image

Note that in this case, the border is in a Grid and center horizontally and vertically.

The first method always works. Though it's using Storyboard and it's kind of weighty.

The second method works in November update since the visual returned by calling ElementCompositionPreview.GetElementVisual() is a separate visual and the origin point is based on the original position of visual, which means that even though its position in its parent changes, the visual can stay it's changed offset.

But now in Anniversary update:

In builds 14332 and later, the visual returned by ElementCompositionPreview.GetElementVisual() is the same visual that is manipulated by XAML for layout purposes.

That means the visual I get from XAML should has a right offset and size which correspond to XAML. And when you make changes in XAML, the visual properties will changes too.

As a result, if I continue to code this to animation the border's offset.x to value of 100:

 var animation = _compositor.CreateScalarKeyFrameAnimation();
animation.InsertKeyFrame(1.0f, 100f);
animation.Duration = TimeSpan.FromMilliseconds(500);
_borderVisual.StartAnimation("Offset.x", animation);

The final position of border is (0,100) in Grid's coordinate, which is :

image

To achieve the original need, I should change the animation to this:

animation.InsertExpressionKeyFrame(1.0f, "this.StartingValue + 100f");

It kind of works, and however, if you continue to toggle the animation, the border's offset.x will be continued to set to the new value since the StartingValue changes every time you call StartAnimation() method.

In addition, if you try to re-size the window after the animation being started, the border's offset will be reset to the original value and can't stay on the final value.

The situation talking above is NOT the worse part.

Because both the caller and XAML are manipulating the same Visual, it is possible that XAML may override values set by the caller.

That means the visual I get from UIElement should have a actual size instead of (0,0) in November update. However, the value in Visual is not synced with XAML value. In SizeChanged event, I can get the UIElmenet's ActualWidth and ActualHeight but the visual size remains (0,0) and will be later updated(because of the "Tick" process?).

The non-sync value updating process puzzles me though.

I want to animate the rotation of Ellipse by its center, and then I should set it's CenterPoint property to (Size.X / 2,Size.Y / 2). However, I have no idea when the Size of the Ellipse visual is updated even when the SizeChanged event has been fired.

As a workaround, I should use XAML size instead of Visual size to set the center point:

_borderVisual.CenterPoint = new Vector3((float)border.ActualWidth / 2, (float)border.ActualHeight / 2f, 0f);

In conclusion, what sense does this Interop Behavior change makes?

@JohnnyWestlake

This comment has been minimized.

Show comment
Hide comment
@JohnnyWestlake

JohnnyWestlake Aug 16, 2016

Not an answer to all of your above, but considering this:

I want to animate the rotation of Ellipse by it's center, and then I should set it's CenterPoint property to (Size.X / 2,Size.Y / 2). However, I have no idea when the Size of the Ellipse visual is updated when the SizeChanged event is fired.

You don't particularly need to care what the size if you take a more efficient expression animation route that will automatically handle size changes for you

_centeringAnimation = visual.Compositor.CreateExpressionAnimation();
_centeringAnimation.SetReferenceParameter("Visual", visual);
_centeringAnimation.Expression = $"(Vector3(Visual.Size.X * 0.5f, Visual.Size.Y * 0.5f, 1f))";
 visual.StartAnimation(nameof(Visual.CenterPoint), _centeringAnimation);

I personally manage it's lifecycle through a behaviour which creates the animation on OnAttached() and appropriately stops and disposes the animation on OnDetaching(), and also lets me specify the center the point the same way as XAML transforms (X,Y from a 0 to 1 range).

(The docs read like you should be able to do it with a Vector2 targeting Centerpoint.xy, but that just does not work.)

Of course, that only works when size actually updates. I've had strange instances where the visual size _never updates to match the ActualHeight/ActualWidth/RenderSize, but that's definitely an exception rather than the rule_

JohnnyWestlake commented Aug 16, 2016

Not an answer to all of your above, but considering this:

I want to animate the rotation of Ellipse by it's center, and then I should set it's CenterPoint property to (Size.X / 2,Size.Y / 2). However, I have no idea when the Size of the Ellipse visual is updated when the SizeChanged event is fired.

You don't particularly need to care what the size if you take a more efficient expression animation route that will automatically handle size changes for you

_centeringAnimation = visual.Compositor.CreateExpressionAnimation();
_centeringAnimation.SetReferenceParameter("Visual", visual);
_centeringAnimation.Expression = $"(Vector3(Visual.Size.X * 0.5f, Visual.Size.Y * 0.5f, 1f))";
 visual.StartAnimation(nameof(Visual.CenterPoint), _centeringAnimation);

I personally manage it's lifecycle through a behaviour which creates the animation on OnAttached() and appropriately stops and disposes the animation on OnDetaching(), and also lets me specify the center the point the same way as XAML transforms (X,Y from a 0 to 1 range).

(The docs read like you should be able to do it with a Vector2 targeting Centerpoint.xy, but that just does not work.)

Of course, that only works when size actually updates. I've had strange instances where the visual size _never updates to match the ActualHeight/ActualWidth/RenderSize, but that's definitely an exception rather than the rule_

@sernaj

This comment has been minimized.

Show comment
Hide comment
@sernaj

sernaj Aug 17, 2016

Contributor

I want to answer your overall question about the change and the philosophy behind it. The reason for the sharing of the Offset property was to allow implicit animations to run as a result of Layout changes - this would allow you to run an input driven animation as the user resizes the window. Implicit animations were introduced in the Anniversary edition update. The downside is that this means using the Offset property becomes much trickier than in 10586 as you now need to pay attention to what XAML layout is doing or create your Offset on a canvas or panel layout doesn't touch. We've written this up here on MSDN

That said, this is not a closed book on how we want to do things, especially as more and more users are adopting the API and we're completely open to listening to any alternative approaches or suggestions here for future releases.

Contributor

sernaj commented Aug 17, 2016

I want to answer your overall question about the change and the philosophy behind it. The reason for the sharing of the Offset property was to allow implicit animations to run as a result of Layout changes - this would allow you to run an input driven animation as the user resizes the window. Implicit animations were introduced in the Anniversary edition update. The downside is that this means using the Offset property becomes much trickier than in 10586 as you now need to pay attention to what XAML layout is doing or create your Offset on a canvas or panel layout doesn't touch. We've written this up here on MSDN

That said, this is not a closed book on how we want to do things, especially as more and more users are adopting the API and we're completely open to listening to any alternative approaches or suggestions here for future releases.

@validvoid

This comment has been minimized.

Show comment
Hide comment
@validvoid

validvoid Aug 17, 2016

@sernaj So is that possible to separately return a (child) Visual for us to do any additive manipulations as build 10586 did before?

And I wonder is there any way to contribute localization for documents on MSDN since many newly added docs about Windows 10 development are in English.

validvoid commented Aug 17, 2016

@sernaj So is that possible to separately return a (child) Visual for us to do any additive manipulations as build 10586 did before?

And I wonder is there any way to contribute localization for documents on MSDN since many newly added docs about Windows 10 development are in English.

@JohnnyWestlake

This comment has been minimized.

Show comment
Hide comment
@JohnnyWestlake

JohnnyWestlake Aug 17, 2016

Personally I think it would have been nicer to have two separate properties, the current Offset, and then RenderOffset (because I can't think of a good name and really it should be called Offset, and the current Offset should be called Position), which works similarly to how a RenderTransform would / is additive to the Offset property. (Presumably how Offset used to work?). Then you could both care / not care about XAML depending on what you want to do. Though I'm guessing most of us want to not care.

Granted, wrapping your object in a Border / Canvas also works fine, but especially with things like DataTemplates, it's a lot of useless extra inside the VisualTree that takes CPU to create and manage and render, and additional memory.

JohnnyWestlake commented Aug 17, 2016

Personally I think it would have been nicer to have two separate properties, the current Offset, and then RenderOffset (because I can't think of a good name and really it should be called Offset, and the current Offset should be called Position), which works similarly to how a RenderTransform would / is additive to the Offset property. (Presumably how Offset used to work?). Then you could both care / not care about XAML depending on what you want to do. Though I'm guessing most of us want to not care.

Granted, wrapping your object in a Border / Canvas also works fine, but especially with things like DataTemplates, it's a lot of useless extra inside the VisualTree that takes CPU to create and manage and render, and additional memory.

@sernaj

This comment has been minimized.

Show comment
Hide comment
@sernaj

sernaj Aug 17, 2016

Contributor

We're looking at several approaches and hope to run them by the community with their plusses and minuses to get your feedback. I'll be sure to loop folks in when we have them ready.

Contributor

sernaj commented Aug 17, 2016

We're looking at several approaches and hope to run them by the community with their plusses and minuses to get your feedback. I'll be sure to loop folks in when we have them ready.

@JuniperPhoton

This comment has been minimized.

Show comment
Hide comment
@JuniperPhoton

JuniperPhoton Aug 18, 2016

@JohnnyWestlake I agree with you. The Anniversary update Offset should be Position which indicate the position of the visual in its parent, and the Offset property should behavior the same as it did in November update.

JuniperPhoton commented Aug 18, 2016

@JohnnyWestlake I agree with you. The Anniversary update Offset should be Position which indicate the position of the visual in its parent, and the Offset property should behavior the same as it did in November update.

@sernaj

This comment has been minimized.

Show comment
Hide comment
@sernaj

sernaj Mar 15, 2017

Contributor

I wanted to circle back to this issue and update everyone that we have a new fix for Offset sharing/Stomping in the Creator's update:
While we don't have the new stomping fix officially documented yet, that's coming in the next few weeks along with a sample. Here's a quick synopsis of it so you can try this out now on any recent fast track insider build (15043 or later.)
You can now use ElementCompositionPreview to inject a Translation property into the PropertySet of the Visual you're working with for example:
ElementCompositionPreview.SetIsTranslationEnabled(myInteropVisual, true);
This adds a translation property to the propertyset that can be used like Offset. Strongly recommend giving it a value on first use to avoid creation timing problems so that it's ready when you need it. For example:
var myInteropVisualPropertySet = ElementCompositionPreview.GetElementVisual(myInteropVisual).Properties; myInteropVisualPropertySet.InsertVector3("Translation", Vector3.Zero);
Then you can use Translation like Offset. Love to hear your feedback if you try this out. We think this will be easier as it lives with ElementCompositionPreview and doesn't make you add elements to your mark up.

Let me know if you have any feedback on the new property insertion.

Contributor

sernaj commented Mar 15, 2017

I wanted to circle back to this issue and update everyone that we have a new fix for Offset sharing/Stomping in the Creator's update:
While we don't have the new stomping fix officially documented yet, that's coming in the next few weeks along with a sample. Here's a quick synopsis of it so you can try this out now on any recent fast track insider build (15043 or later.)
You can now use ElementCompositionPreview to inject a Translation property into the PropertySet of the Visual you're working with for example:
ElementCompositionPreview.SetIsTranslationEnabled(myInteropVisual, true);
This adds a translation property to the propertyset that can be used like Offset. Strongly recommend giving it a value on first use to avoid creation timing problems so that it's ready when you need it. For example:
var myInteropVisualPropertySet = ElementCompositionPreview.GetElementVisual(myInteropVisual).Properties; myInteropVisualPropertySet.InsertVector3("Translation", Vector3.Zero);
Then you can use Translation like Offset. Love to hear your feedback if you try this out. We think this will be easier as it lives with ElementCompositionPreview and doesn't make you add elements to your mark up.

Let me know if you have any feedback on the new property insertion.

@JohnnyWestlake

This comment has been minimized.

Show comment
Hide comment
@JohnnyWestlake

JohnnyWestlake Mar 15, 2017

Slightly begs the question as to why not just put a Translation property on Visual (and what RelativeOffsetAdjustment actually is?) buuuuuuuut, it does work well enough so far =D

JohnnyWestlake commented Mar 15, 2017

Slightly begs the question as to why not just put a Translation property on Visual (and what RelativeOffsetAdjustment actually is?) buuuuuuuut, it does work well enough so far =D

@jlnostr

This comment has been minimized.

Show comment
Hide comment
@jlnostr

jlnostr Mar 15, 2017

@sernaj Great to hear that news! Even if I didn't tested out the new APIs, it would be interesting to hear what the other devs in this discussion think about inserting a Vector3.Zero by default to prevent the "creation timing" issues you mentioned.

jlnostr commented Mar 15, 2017

@sernaj Great to hear that news! Even if I didn't tested out the new APIs, it would be interesting to hear what the other devs in this discussion think about inserting a Vector3.Zero by default to prevent the "creation timing" issues you mentioned.

@JuniperPhoton

This comment has been minimized.

Show comment
Hide comment
@JuniperPhoton

JuniperPhoton Mar 16, 2017

@sernaj I have tried this and it work as I expected(finally, LOL). And also as what @JohnnyWestlake said, why not just add a property named TranslationX/Y to visual? At last, although a good sample is enough, a doc about those is needed. Looking forward to it.

JuniperPhoton commented Mar 16, 2017

@sernaj I have tried this and it work as I expected(finally, LOL). And also as what @JohnnyWestlake said, why not just add a property named TranslationX/Y to visual? At last, although a good sample is enough, a doc about those is needed. Looking forward to it.

@sernaj

This comment has been minimized.

Show comment
Hide comment
@sernaj

sernaj Mar 22, 2017

Contributor

@JohnnyWestlake @JuniperPhoton we're looking to keep the Visual itself fairly lightweight and agnostic to the XAML layout tick. We're discovering most scenarios that encounter layout stomping use Offset animations happen on Visuals obtained via ElementCompositionPreview.GetElementVisual and are backing a UIElement. If you're building custom comp content via SetChildVisual you're never stomped. So instead of adding a second Offset or Translation to the Visual (where it would be used in some scenarios only) we're looking at reconciling this directly on UIElement. So, for example, you may see an additional property there in future that also works with Win.UI.Comp animations. This takes us back to title of the topic, we're seeing the future of interop as pushing Composition goodness scenarios up to the Framework in places like UIElement where it's most accessible, while keeping the Visual Layer itself fairly lean. This is one of the reasons we landed on the current PropertySet fix, so that he extra property was used when needed so that long term when we push Comp goodness up we don't have to deprecate properties on the Visual (and can keep it lean.) BTW we will be pulling in the community for feedback on the next round of interop work, so stay tuned for that.

Contributor

sernaj commented Mar 22, 2017

@JohnnyWestlake @JuniperPhoton we're looking to keep the Visual itself fairly lightweight and agnostic to the XAML layout tick. We're discovering most scenarios that encounter layout stomping use Offset animations happen on Visuals obtained via ElementCompositionPreview.GetElementVisual and are backing a UIElement. If you're building custom comp content via SetChildVisual you're never stomped. So instead of adding a second Offset or Translation to the Visual (where it would be used in some scenarios only) we're looking at reconciling this directly on UIElement. So, for example, you may see an additional property there in future that also works with Win.UI.Comp animations. This takes us back to title of the topic, we're seeing the future of interop as pushing Composition goodness scenarios up to the Framework in places like UIElement where it's most accessible, while keeping the Visual Layer itself fairly lean. This is one of the reasons we landed on the current PropertySet fix, so that he extra property was used when needed so that long term when we push Comp goodness up we don't have to deprecate properties on the Visual (and can keep it lean.) BTW we will be pulling in the community for feedback on the next round of interop work, so stay tuned for that.

@daneuber

This comment has been minimized.

Show comment
Hide comment
@daneuber

daneuber Aug 7, 2017

Member

Each release we're continuing to improve the XAML-Composition interop story, and hopefully the introduction of translate as shown in this sample has mitigated some of the immediate concerns. Feel free to open a new issue if you have additional feedback.

Member

daneuber commented Aug 7, 2017

Each release we're continuing to improve the XAML-Composition interop story, and hopefully the introduction of translate as shown in this sample has mitigated some of the immediate concerns. Feel free to open a new issue if you have additional feedback.

@daneuber daneuber closed this Aug 7, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment