microsoft / WindowsCompositionSamples

The Windows Composition Samples have moved here: https://github.com/microsoft/WindowsAppSDK-Samples/tree/main/Samples/SceneGraph
https://github.com/microsoft/WindowsAppSDK-Samples/tree/main/Samples/SceneGraph
MIT License
1.12k stars 287 forks source link

How to set a property without using an animation? #328

Closed assassin316 closed 5 years ago

assassin316 commented 5 years ago

Question, how can we set a value for a property on Visual without using an animation? For example this works for me (for a Translation) but I feel there must be a better way. I'm using an animation of 1 millisecond to set a value immediately:

ElementCompositionPreview.SetIsTranslationEnabled(MyRectangle, true);

var visual = ElementCompositionPreview.GetElementVisual(MyRectangle);
var anim = compositor.CreateScalarKeyFrameAnimation();

anim.InsertKeyFrame(1.0f, 100f);
anim.Duration = TimeSpan.FromMilliseconds(1);

visual.StartAnimation("Translation.Y", anim);
daneuber commented 5 years ago

Hi @assassin316 . Is your question specifically about Translation or more broad? In general Visual properties can be set using straighforward myVisual.Size = new Vector2(100,100); style syntax. For the Translation example above, you're using the ECP SetIsTranslationEnabled method to access the XAML element transform post-layout. In this case you could alternatively get the backing Visual using ECP.GetElementVisual and then directly set myVisual.Transform Matrix to your desired 4x4 matrix. This would look something like below:

var visual = ElementCompositionPreview.GetElementVisual(MyRectangle);
            Matrix4x4 transformMatrix =
                           new Matrix4x4(
                               1, 0, 0, 0,
                               0, 1, 0, 0,
                               0, 0, 1, 0,
                               0, 0, 0, 1) *
                           Matrix4x4.CreateTranslation(0,500,0);
            visual.TransformMatrix = transformMatrix;

Does that address your question or can you provide more details on what you're trying to achieve?

Massimo37 commented 5 years ago

Thanks @daneuber for the reply. I guess that would work for any of the base properties (scale, rotate, etc..), except Opacity, but I had tried the following which didn't work for all cases:

// Attempt to use in order to specify the "initial" value
// instead of animating the "from" values with a 1 millisecond animation
private static void SetFromVector3(this FrameworkElement element, string targetProperty, Func<Vector3> initialValueFunc, Func<Vector3, Vector3> updateValueFunc)
{
    var props = ElementCompositionPreview.GetElementVisual(element).Properties;

    if (props.TryGetVector3(targetProperty, out var vector) == CompositionGetValueStatus.Succeeded)
    {
        props.InsertVector3(targetProperty, updateValueFunc(vector));
    }
    else
    {
        props.InsertVector3(targetProperty, initialValueFunc());
    }
}

// Attempt to use in order to specify the "initial" value
// instead of animating the "from" values with a 1 millisecond animation
private static void SetFromScalar(this FrameworkElement element, string targetProperty, Func<float> initialValueFunc, Func<float> updateValueFunc)
{
    var props = ElementCompositionPreview.GetElementVisual(element).Properties;

    if (props.TryGetScalar(targetProperty, out var scalar) == CompositionGetValueStatus.Succeeded)
    {
        props.InsertScalar(targetProperty, updateValueFunc());
    }
    else
    {
        props.InsertScalar(targetProperty, initialValueFunc());
    }
}

With these two functions, I was hoping to do something as such:

// Set a Y translation of 100
_myElement.SetFromVector3("Translation",
    initialValueFunc: () => Vector3.Zero,
    updateValueFunc: vect => new Vector3(vect.X, 100f, vect.Z));

OR

// Set a rotation of 90
_myElement.SetFromScalar("Rotation",
    initialValueFunc: () => 0f,
    updateValueFunc: () => 90.0f);

Therefore if a property didn't exist in the PropertySet (it would set an initial value). If it exists, it would just set the new value. Would such an idea work?

assassin316 commented 5 years ago

I finally figured it out, MUCH simpler than expected :)

// OPACITY
visual.Opacity = ...;

// TRANSLATION
visual.Properties.InsertVector3("Translation", new Vector3(...);

//ROTATION
visual.RotationAngleInDegrees = ...;

//SCALE
visual.Scale = new Vector3(...);
daneuber commented 5 years ago

@assassin316 great to hear! Depending on your usage you may also be able to use visual.Offset in place of your Translation property.

daneuber commented 5 years ago

Seems like the original question was addressed. Closing this out.