nalka
nalka

Reputation: 2380

Easing function without inheriting from Freezable?

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

Answers (0)

Related Questions