Fixed jerky zoom animation (#5483)

This commit is contained in:
martinchrzan 2020-08-06 20:53:16 +02:00 committed by GitHub
parent d6e46d73b5
commit 066aeec1e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 9 deletions

View file

@ -19,7 +19,7 @@ namespace ColorPicker.Behaviors
var sender = ((MoveWindowBehavior)d).AssociatedObject;
var move = new DoubleAnimation(sender.Left, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.Stop);
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
sender.BeginAnimation(Window.LeftProperty, move, HandoffBehavior.SnapshotAndReplace);
sender.BeginAnimation(Window.LeftProperty, move, HandoffBehavior.Compose);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-security#:~:text=Dependency%20properties%20should%20generally%20be%20considered%20to%20be,make%20security%20guarantees%20about%20a%20dependency%20property%20value.")]
@ -30,7 +30,7 @@ namespace ColorPicker.Behaviors
var sender = ((MoveWindowBehavior)d).AssociatedObject;
var move = new DoubleAnimation(sender.Top, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.Stop);
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
sender.BeginAnimation(Window.TopProperty, move, HandoffBehavior.SnapshotAndReplace);
sender.BeginAnimation(Window.TopProperty, move, HandoffBehavior.Compose);
}
public double Left

View file

@ -25,7 +25,7 @@ namespace ColorPicker.Behaviors
};
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
sender.BeginAnimation(FrameworkElement.WidthProperty, move, HandoffBehavior.SnapshotAndReplace);
sender.BeginAnimation(FrameworkElement.WidthProperty, move, HandoffBehavior.Compose);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-security#:~:text=Dependency%20properties%20should%20generally%20be%20considered%20to%20be,make%20security%20guarantees%20about%20a%20dependency%20property%20value.")]
@ -42,7 +42,7 @@ namespace ColorPicker.Behaviors
};
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
sender.BeginAnimation(FrameworkElement.HeightProperty, move, HandoffBehavior.SnapshotAndReplace);
sender.BeginAnimation(FrameworkElement.HeightProperty, move, HandoffBehavior.Compose);
}
public double Width

View file

@ -100,6 +100,8 @@
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="Helpers\IThrottledActionInvoker.cs" />
<Compile Include="Helpers\ThrottledActionInvoker.cs" />
<Compile Include="Settings\IUserSettings.cs" />
<Compile Include="Settings\SettingItem.cs" />
<Compile Include="Settings\UserSettings.cs" />

View file

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace ColorPicker.Helpers
{
public interface IThrottledActionInvoker
{
void ScheduleAction(Action action, int miliseconds);
}
}

View file

@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ComponentModel.Composition;
using System.Windows.Threading;
namespace ColorPicker.Helpers
{
[Export(typeof(IThrottledActionInvoker))]
public sealed class ThrottledActionInvoker : IThrottledActionInvoker
{
private Action _actionToRun;
private DispatcherTimer _timer;
public ThrottledActionInvoker()
{
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
}
public void ScheduleAction(Action action, int miliseconds)
{
if (_timer.IsEnabled)
{
_timer.Stop();
}
_actionToRun = action;
_timer.Interval = new TimeSpan(0, 0, 0, 0, miliseconds);
_timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
_actionToRun.Invoke();
}
}
}

View file

@ -18,6 +18,7 @@ namespace ColorPicker.Helpers
[Export(typeof(ZoomWindowHelper))]
public class ZoomWindowHelper
{
private const int ZoomWindowChangeDelayInMS = 50;
private const int ZoomFactor = 2;
private const int BaseZoomImageSize = 50;
private const int MaxZoomLevel = 3;
@ -25,6 +26,7 @@ namespace ColorPicker.Helpers
private readonly IZoomViewModel _zoomViewModel;
private readonly AppStateHandler _appStateHandler;
private readonly IThrottledActionInvoker _throttledActionInvoker;
private int _currentZoomLevel = 0;
private int _previousZoomLevel = 0;
@ -38,10 +40,11 @@ namespace ColorPicker.Helpers
private double _previousScaledY;
[ImportingConstructor]
public ZoomWindowHelper(IZoomViewModel zoomViewModel, AppStateHandler appStateHandler)
public ZoomWindowHelper(IZoomViewModel zoomViewModel, AppStateHandler appStateHandler, IThrottledActionInvoker throttledActionInvoker)
{
_zoomViewModel = zoomViewModel;
_appStateHandler = appStateHandler;
_throttledActionInvoker = throttledActionInvoker;
_appStateHandler.AppClosed += AppStateHandler_AppClosed;
_appStateHandler.AppHidden += AppStateHandler_AppClosed;
}
@ -174,10 +177,15 @@ namespace ColorPicker.Helpers
PowerToysTelemetry.Log.WriteEvent(new ColorPickerZoomOpenedEvent());
}
_zoomWindow.DesiredLeft = _lastLeft;
_zoomWindow.DesiredTop = _lastTop;
_zoomViewModel.DesiredHeight = BaseZoomImageSize * _zoomViewModel.ZoomFactor;
_zoomViewModel.DesiredWidth = BaseZoomImageSize * _zoomViewModel.ZoomFactor;
_throttledActionInvoker.ScheduleAction(
() =>
{
_zoomWindow.DesiredLeft = _lastLeft;
_zoomWindow.DesiredTop = _lastTop;
_zoomViewModel.DesiredHeight = BaseZoomImageSize * _zoomViewModel.ZoomFactor;
_zoomViewModel.DesiredWidth = BaseZoomImageSize * _zoomViewModel.ZoomFactor;
},
ZoomWindowChangeDelayInMS);
}
private void ZoomWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)