Reputation: 2380
I am trying to implement a custom IEasingFunction
that is basically a wrapper for an other IEasingFunction
but it adds a pause at the beginning and end of the animation. I don't want it to inherit from EasingFunctionBase
because having an EasingMode on the PausingEasingFunction is non-sense. The pauses are the same, no matter what mode you'd use and the wrapped one can have its mode specified on its own.
Here's how it looks : PausingEasingFunction.cs
public class PausingEasingFunction : DependencyObject, IEasingFunction
{
public static readonly DependencyProperty WrappedEasingFunctionProperty = DependencyProperty.Register(nameof(WrappedEasingFunction), typeof(IEasingFunction), typeof(PausingEasingFunction));
public static readonly DependencyProperty StartPauseProperty = DependencyProperty.Register(nameof(StartPause), typeof(double), typeof(PausingEasingFunction));
public static readonly DependencyProperty EndPauseProperty = DependencyProperty.Register(nameof(EndPause), typeof(double), typeof(PausingEasingFunction));
public IEasingFunction WrappedEasingFunction
{
get => (IEasingFunction)GetValue(WrappedEasingFunctionProperty);
set => SetValue(WrappedEasingFunctionProperty, value);
}
public double StartPause
{
get => (double)GetValue(StartPauseProperty);
set => SetValue(StartPauseProperty, value);
}
public double EndPause
{
get => (double)GetValue(EndPauseProperty);
set => SetValue(EndPauseProperty, value);
}
public double Ease(double normalizedTime)
{
if (normalizedTime < StartPause)
{
return 0;
}
else if (normalizedTime <= 1 - EndPause)
{
if (WrappedEasingFunction == null)
{
return (normalizedTime - StartPause) / (1 - StartPause - EndPause);
}
else
{
return WrappedEasingFunction.Ease((normalizedTime - StartPause) / (1 - StartPause - EndPause));
}
}
else
{
return 1;
}
}
}
The problem is, when I try to use it in an animation using the following xaml (local:
refers to the xmlns pointing to the clr namespace containing PausingEasingFunction
) :
<TextBlock Text="Hello I am some animated text!">
<TextBlock.RenderTransform>
<TranslateTransform X="0" x:Name="transform"/>
</TextBlock.RenderTransform>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="X" Storyboard.TargetName="transform" RepeatBehavior="Forever" From="0" To="100" Duration="0:0:10">
<DoubleAnimation.EasingFunction>
<local:PausingEasingFunction>
<local:PausingEasingFunction.WrappedEasingFunction>
<SineEase EasingMode="EaseInOut"/>
</local:PausingEasingFunction.WrappedEasingFunction>
</local:PausingEasingFunction>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
An InvalidOperationException is thrown, telling me that a Freezable can't be frozen. However, if I change PausingEasingFunction.cs to inherit from Freezable
instead of DependencyObject
and implement CreateInstanceCore this way :
protected override Freezable CreateInstanceCore()
{
return new PausingEasingFunction();
}
The exception isn't thrown anymore. After some investigation, I found out that WPF still tries to freeze things even if they have CanFreeze = false but I'm not sure if it's really the problem here...
Is it a WPF bug? Am I doing something wrong? Or why am I forced to inherit from Freezable?
Upvotes: 1
Views: 108