Я использую 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("");
}
}
}