Skip to content

Commit

Permalink
fix: Don't use cached value when it's no longer valid
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Sep 7, 2021
1 parent 0789a59 commit 8b94591
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using SamplesApp.UITests.TestFramework;
using Uno.UITest.Helpers;
using Uno.UITest.Helpers.Queries;

namespace SamplesApp.UITests.Windows_UI_Xaml_Media_Animation
{
[TestFixture]
public partial class SetTarget_After_Start : SampleControlUITestBase
{
[Test]
[AutoRetry]
public async Task When_Target_Is_Set_After_Start()
{
Run("UITests.Shared.Windows_UI_Xaml_Media_Animation.SetTargetProperty");
var playBtn = _app.Marked("playButton");

var animatedRect = _app.Query("AnimatedRect");
var animatedRectRect = animatedRect.Single().Rect.ToRectangle();

var container = _app.Query("Container");
var containerRect = container.Single().Rect.ToRectangle();

// 5 is tolerance.
Assert.LessOrEqual(Math.Abs(animatedRectRect.X - containerRect.X), 5);
Assert.LessOrEqual(Math.Abs(animatedRectRect.Y - containerRect.Y), 5);

playBtn.FastTap();
await Task.Delay(1000); // Wait for animation.

animatedRectRect = _app.Query("AnimatedRect").Single().Rect.ToRectangle();

// The rect should move horizontally.
Assert.LessOrEqual(Math.Abs(animatedRectRect.Right - containerRect.Right), 5);
Assert.LessOrEqual(Math.Abs(animatedRectRect.Y - containerRect.Y), 5);

// Change the direction
_app.Marked("IsDirectionHorizontalToggle").SetDependencyPropertyValue("IsOn", "True");

await Task.Delay(1000);

animatedRectRect = _app.Query("AnimatedRect").Single().Rect.ToRectangle();

// The rect should move vertically.
Assert.LessOrEqual(Math.Abs(animatedRectRect.Right - containerRect.Right), 5);
Assert.LessOrEqual(Math.Abs(animatedRectRect.Bottom - containerRect.Bottom), 5);

// Toggle the rect
var animatedRect2 = _app.Query("AnimatedRect2");
var animatedRect2Rect = animatedRect2.Single().Rect.ToRectangle();

var container2 = _app.Query("Container2");
var container2Rect = container2.Single().Rect.ToRectangle();

Assert.LessOrEqual(Math.Abs(animatedRect2Rect.X - container2Rect.X), 5);
Assert.LessOrEqual(Math.Abs(animatedRect2Rect.Y - container2Rect.Y), 5);

_app.Marked("AnimatedRectSwitch").SetDependencyPropertyValue("IsOn", "True");

await Task.Delay(1000);

animatedRect2Rect = _app.Query("AnimatedRect2").Single().Rect.ToRectangle();

Assert.LessOrEqual(Math.Abs(animatedRect2Rect.X - container2Rect.X), 5);
Assert.LessOrEqual(Math.Abs(animatedRect2Rect.Bottom - container2Rect.Bottom), 5);
}
}
}
11 changes: 9 additions & 2 deletions src/SamplesApp/UITests.Shared/UITests.Shared.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_Devices\GeolocatorTests.xaml">
<Page Include="$(MSBuildThisFileDirectory)Windows_Devices\GeolocatorTests.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
Expand Down Expand Up @@ -3961,6 +3961,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media_Animation\SetTargetProperty.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Shapes\Basic_Shapes.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down Expand Up @@ -6641,6 +6645,9 @@
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media_Animation\EasingDoubleKeyFrame_CompositeTransform_Container.xaml.cs">
<DependentUpon>EasingDoubleKeyFrame_CompositeTransform_Container.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Media_Animation\SetTargetProperty.xaml.cs">
<DependentUpon>SetTargetProperty.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Windows_UI_Xaml_Shapes\Basic_Shapes.xaml.cs">
<DependentUpon>Basic_Shapes.xaml</DependentUpon>
</Compile>
Expand Down Expand Up @@ -7665,4 +7672,4 @@
<None Include="$(MSBuildThisFileDirectory)ItemExclusions.props" />
</ItemGroup>
<Import Project="ItemExclusions.props" />
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<Page
x:Class="UITests.Shared.Windows_UI_Xaml_Media_Animation.SetTargetProperty"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UITests.Windows_UI_Xaml_Media_Animation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<StackPanel Grid.Row="0">
<Button Content="Play/Replay" x:Name="playButton" Click="{x:Bind PlayAnimation}" />
<ToggleSwitch x:Name="IsDirectionHorizontalToggle"
Header="Direction"
Toggled="{x:Bind OnDirectionOrRectChanged}"
OnContent="Vertical"
OffContent="Horizontal" />
<ToggleSwitch x:Name="AnimatedRectSwitch"
Header="AnimatedRect"
Toggled="{x:Bind OnDirectionOrRectChanged}"
OnContent="Yellow"
OffContent="Pink" />
</StackPanel>

<Border Grid.Row="1"
x:Name="Container"
BorderThickness="1"
BorderBrush="Black"
Margin="16"
Background="Pink">
<Rectangle x:Name="AnimatedRect"
Width="50"
Height="50"
Fill="SkyBlue"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</Border>

<Border Grid.Row="2"
x:Name="Container2"
BorderThickness="1"
BorderBrush="Black"
Margin="16"
Background="Yellow">
<Rectangle x:Name="AnimatedRect2"
Width="50"
Height="50"
Fill="SkyBlue"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</Border>

</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Uno.UI.Samples.Controls;
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.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace UITests.Shared.Windows_UI_Xaml_Media_Animation
{
[Sample("Animations")]
public sealed partial class SetTargetProperty : Page
{
private static readonly TimeSpan AnimationDuration = TimeSpan.FromMilliseconds(1000);

private TranslateTransform _translateTransform;
private TranslateTransform _translateTransform2;

private Storyboard _storyboard = new Storyboard();
private DoubleAnimation _translateAnimation;

public SetTargetProperty()
{
this.InitializeComponent();
this.Loaded += (s, e) => Setup();
}

private void Setup()
{
AnimatedRect.RenderTransform = _translateTransform = new TranslateTransform();
AnimatedRect2.RenderTransform = _translateTransform2 = new TranslateTransform();

_translateAnimation = new DoubleAnimation()
{
Duration = new Duration(AnimationDuration),
};
Storyboard.SetTarget(_translateAnimation, _translateTransform);
UpdateTranslateAnimationTargetProperty();
_storyboard.Children.Add(_translateAnimation);
}

private void OnDirectionOrRectChanged()
{
var playing = StopRunningAnimation();
UpdateTranslateAnimationTargetProperty();
if (playing)
{
PlayAnimation();
}
}

private void UpdateTranslateAnimationTargetProperty()
{
if (_translateAnimation == null) return;

var property = IsDirectionHorizontal() ? nameof(_translateTransform.X) : nameof(_translateTransform.Y);
Storyboard.SetTargetProperty(_translateAnimation, property);
Storyboard.SetTarget(_translateAnimation, AnimatedRectSwitch.IsOn ? _translateTransform2 : _translateTransform);
}


private void PlayAnimation()
{
var total = IsDirectionHorizontal() ? Container.ActualSize.X : Container.ActualSize.Y;
var occupied = IsDirectionHorizontal() ? AnimatedRect.Width : AnimatedRect.Height;
var length = total - occupied;

_translateAnimation.From = 0;
_translateAnimation.To = length;

_storyboard.Begin();
}

private bool StopRunningAnimation()
{
if (_storyboard.GetCurrentState() != ClockState.Stopped)
{
// we want to Pause() the animation midway to avoid the jarring feeling
// but since paused state will still yield ClockState.Active
// we have to actually use Stop() in order to differentiate

// pause & snapshot the animated values in the middle of animation
_storyboard.Pause();
var offset = TranslateOffset;

// restore the values after stopping it
_storyboard.Stop();
TranslateOffset = offset;

return true;
}

return false;
}

// helpers
private bool IsDirectionHorizontal() => !IsDirectionHorizontalToggle.IsOn;
private bool IsCurrentAnimationDirectionHorizontal() => Storyboard.GetTargetProperty(_translateAnimation) switch
{
nameof(_translateTransform.X) => true,
nameof(_translateTransform.Y) => false,

_ => throw new ArgumentOutOfRangeException(nameof(Storyboard.TargetPropertyProperty)),
};

private double TranslateOffset
{
get => IsCurrentAnimationDirectionHorizontal() ? _translateTransform.X : _translateTransform.Y;
set
{
if (IsCurrentAnimationDirectionHorizontal()) _translateTransform.X = value;
else _translateTransform.Y = value;
}
}
}
}
24 changes: 19 additions & 5 deletions src/Uno.UI/UI/Xaml/Media/Animation/Timeline.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,32 @@ internal BindingPath PropertyInfo
{
get
{
if (_propertyInfo == null)
// Don't use the cached _propertyInfo if TargetProperty or Target has the changed.
var targetPropertyPath = Storyboard.GetTargetProperty(this);
InitTarget();
var target = Target ?? GetTargetFromName();

if (_propertyInfo == null || _propertyInfo.Path != targetPropertyPath)
{
InitTarget();
var target = Target ?? GetTargetFromName();
if (_propertyInfo != null)
{
_propertyInfo.DataContext = null;
}

_propertyInfo = new BindingPath(
path: Storyboard.GetTargetProperty(this),
path: targetPropertyPath,
fallbackValue: null,
precedence: DependencyPropertyValuePrecedences.Animations,
allowPrivateMembers: false
);
)
{
DataContext = target,
};
return _propertyInfo;
}

if (_propertyInfo.DataContext != target)
{
_propertyInfo.DataContext = target;
}

Expand Down

0 comments on commit 8b94591

Please sign in to comment.