Анимация раскадровки UIElement.PlaneProjection сломана, когда Composition API используется на всех - PullRequest
0 голосов
/ 17 ноября 2018

Я использую Composition API для различных анимаций и эффектов. Я также пытаюсь включить 3D эффект перспективы на тех же элементах. К сожалению, единственный способ воссоздать эффект трехмерной перспективы с помощью API композиции - это использование свойства Visual.TransformMatrix, которое нельзя анимировать AFAIK . Так что для анимируемого эффекта трехмерной перспективы я должен использовать обычную раскадровку, которая нацелена на PlaneProjection, как показано в первой ссылке.

Проблема (которая заняла у меня очень много времени, чтобы выяснить причину) состоит в том, что после завершения раскадровки он вернулся к своему первоначальному значению. FillBehavior был установлен в значение по умолчанию «HoldEnd». Вызов Storyboard.GetCurrentState () показал, что это «заполнение», но на самом деле это не так.

Тогда я понял, что это нарушенное поведение возникает, только если ElementCompositionPreview.GetElementVisual был вызван для UIElement. Даже если я не изменяю какие-либо из свойств Visual или вообще ничего с ним не делаю, просто вызов, который фактически делает невозможным использование анимации раскадровки, нацеленной на UIElement.PlaneProjection, если вы не хотите, чтобы он сбрасывался после завершения.

Копирование и вставка приведенного ниже кода в новый проект UWP, нацеленный на 1809 или 1803, обеспечит полное воспроизведение проекта.

MainPage.xaml

<Page
    x:Class="PlaneProjectionStoryboardBugRepro.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="Transparent">

    <Grid x:Name="LayoutRoot">
        <TextBlock x:Name="StandardText" Visibility="Visible" Foreground="DarkGreen" HorizontalAlignment="Center" TextAlignment="Center" VerticalAlignment="Top" Margin="100" FontSize="24">
            Press the rotate button several times<LineBreak/>
            Notice Storyboard that is rotating the plane projection about Y axis is working properly.<LineBreak/>
            Now try it after pressing the second button.
        </TextBlock>
        <TextBlock x:Name="WarningText" Visibility="Collapsed" Foreground="DarkRed" HorizontalAlignment="Center" TextAlignment="Center" VerticalAlignment="Top" Margin="100" FontSize="24">
            Composition API has been invoked.<LineBreak/>
            Notice that now the rotation Storyboard animation's FillBehavior is broken.<LineBreak/>
            Simply from calling 'ElementCompositionPreview.GetElementVisual'
        </TextBlock>
        <Image x:Name="Logo" Source="Assets\StoreLogo.png"  Height="500" Width="500" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="30">
            <Button Content="Rotate Logo" Margin="12" HorizontalAlignment="Center" Click="Button_Click"/>
            <Button Content="Call 'GetElementVisual' On Logo" Margin="12" HorizontalAlignment="Center" Click="Button_Click_2"/>
            <Button Content="Reset" HorizontalAlignment="Center" Margin="12" Click="Button_Click_3"/>
        </StackPanel>
    </Grid>
</Page>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Hosting;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;

namespace PlaneProjectionStoryboardBugRepro
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.Loaded += MainPage_Loaded;
            this.InitializeComponent();
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            var pp = new PlaneProjection();
            Logo.Projection = pp;
        }

        double EndAngle = 0;

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            EndAngle = (EndAngle == 0) ? 45 : 0;
            var storyboard = new Storyboard();
            var animation = new DoubleAnimation();
            animation.Duration = TimeSpan.FromMilliseconds(500);
            animation.To = EndAngle;
            Storyboard.SetTarget(animation, Logo);
            Storyboard.SetTargetProperty(animation, "(UIElement.Projection).(PlaneProjection.RotationY)");
            storyboard.Children.Add(animation);
            storyboard.Begin();
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            // Simply instantiating a Visual object of the UIElement breaks the Storyboard.
            var visual = ElementCompositionPreview.GetElementVisual(Logo);

            StandardText.Visibility = Visibility.Collapsed;
            WarningText.Visibility = Visibility.Visible;
        }

        async void Button_Click_3(object sender, RoutedEventArgs e)
        {
            await CoreApplication.RequestRestartAsync("");
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...