Skip to content

Animating RenderTransform crashes with No animator registered for the property RenderTransform #8640

Description

@hhyyrylainen

Describe the bug
I'm trying to animate a control sliding in from offscreen but my app crashes on startup.

To Reproduce
Steps to reproduce the behavior:

  1. Create the following style in App.axaml:
        <Style Selector="Border.Popup[IsVisible=true]">
            <Style.Animations>
                <Animation Duration="0:0:0.1" FillMode="None">
                    <KeyFrame Cue="0%">
                        <Setter Property="RenderTransform" Value="translateX(-500px)"/>
                    </KeyFrame>
                    <KeyFrame Cue="100%">
                        <Setter Property="RenderTransform" Value="translateX(0px)"/>
                    </KeyFrame>
                </Animation>
            </Style.Animations>
        </Style>
  1. Add something like this to a window:
            <Border HorizontalAlignment="Center" VerticalAlignment="Center" Background="{DynamicResource SubMenuBackground}"
                    BorderBrush="Black" BorderThickness="1" CornerRadius="5" Classes="Popup"
                    IsVisible="{Binding $parent.IsVisible}">
  1. Start app
  2. Get an exception on startup:
System.InvalidOperationException: No animator registered for the property RenderTransform. Add an animator to the Animation.Animators collection that matches this property to animate it.
   at Avalonia.Animation.Animation.InterpretKeyframes(Animatable control) in /_/src/Avalonia.Animation/Animation.cs:line 283
   at Avalonia.Animation.Animation.Apply(Animatable control, IClock clock, IObservable`1 match, Action onComplete) in /_/src/Avalonia.Animation/Animation.cs:line 326
   at Avalonia.Styling.StyleInstance..ctor(IStyle source, IStyleable target, IReadOnlyList`1 setters, IReadOnlyList`1 animations, IStyleActivator activator) in /_/src/Avalonia.Styling/Styling/StyleInstance.cs:line 54
   at Avalonia.Styling.Style.TryAttach(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Style.cs:line 106
   at Avalonia.Styling.Styles.TryAttach(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styles.cs:line 138
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 30
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 15
   at Avalonia.StyledElement.ApplyStyling() in /_/src/Avalonia.Styling/StyledElement.cs:line 340
   at Avalonia.StyledElement.EndInit() in /_/src/Avalonia.Styling/StyledElement.cs:line 321
   at ThriveLauncher.Views.MainWindow.!XamlIlPopulate(IServiceProvider , MainWindow ) in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Views/MainWindow.axaml:line 54
   at ThriveLauncher.Views.MainWindow.!XamlIlPopulateTrampoline(MainWindow )
   at ThriveLauncher.Views.MainWindow.InitializeComponent(Boolean loadXaml, Boolean attachDevTools) in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Avalonia.NameGenerator/Avalonia.NameGenerator.AvaloniaNameSourceGenerator/MainWindow.g.cs:line 23
   at ThriveLauncher.Views.MainWindow..ctor() in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Views/MainWindow.axaml.cs:line 11
   at ThriveLauncher.App.OnFrameworkInitializationCompleted() in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/App.axaml.cs:line 28
   at Avalonia.Controls.AppBuilderBase`1.Setup() in /_/src/Avalonia.Controls/AppBuilderBase.cs:line 312
   at Avalonia.Controls.AppBuilderBase`1.SetupWithLifetime(IApplicationLifetime lifetime) in /_/src/Avalonia.Controls/AppBuilderBase.cs:line 179
   at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime[T](T builder, String[] args, ShutdownMode shutdownMode) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 208
   at ThriveLauncher.Program.Main(String[] args) in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Program.cs:line 15

So the animation doesn't even need to start, just existing seems to be enough to crash.

I found that I can get around the startup exception by running this code before the app loads:

Animation.RegisterAnimator<TransformAnimator>(prop => typeof(ITransform).IsAssignableFrom(prop.PropertyType));

But that results in an error later, and an error print:

[Animations] Cannot apply animation: Target property owner Avalonia.Visual is not a Transform object. (Border #3663598)

exception with that extra TransformAnimator:

System.ArgumentException: Disposables collection can not contain null values. (Parameter 'disposables')
   at System.Reactive.Disposables.CompositeDisposable.ToList(IEnumerable`1 disposables) in /_/Rx.NET/Source/src/System.Reactive/Disposables/CompositeDisposable.cs:line 107
   at System.Reactive.Disposables.CompositeDisposable..ctor(IEnumerable`1 disposables) in /_/Rx.NET/Source/src/System.Reactive/Disposables/CompositeDisposable.cs:line 83
   at Avalonia.Animation.Animation.Apply(Animatable control, IClock clock, IObservable`1 match, Action onComplete) in /_/src/Avalonia.Animation/Animation.cs:line 353
   at Avalonia.Styling.StyleInstance..ctor(IStyle source, IStyleable target, IReadOnlyList`1 setters, IReadOnlyList`1 animations, IStyleActivator activator) in /_/src/Avalonia.Styling/Styling/StyleInstance.cs:line 54
   at Avalonia.Styling.Style.TryAttach(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Style.cs:line 106
   at Avalonia.Styling.Styles.TryAttach(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styles.cs:line 138
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 30
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target, IStyleHost host) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 25
   at Avalonia.Styling.Styler.ApplyStyles(IStyleable target) in /_/src/Avalonia.Styling/Styling/Styler.cs:line 15
   at Avalonia.StyledElement.ApplyStyling() in /_/src/Avalonia.Styling/StyledElement.cs:line 340
   at Avalonia.StyledElement.EndInit() in /_/src/Avalonia.Styling/StyledElement.cs:line 321
   at ThriveLauncher.Views.MainWindow.!XamlIlPopulate(IServiceProvider , MainWindow ) in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Views/MainWindow.axaml:line 54
   at ThriveLauncher.Views.MainWindow.!XamlIlPopulateTrampoline(MainWindow )
   at ThriveLauncher.Views.MainWindow.InitializeComponent(Boolean loadXaml, Boolean attachDevTools) in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Avalonia.NameGenerator/Avalonia.NameGenerator.AvaloniaNameSourceGenerator/MainWindow.g.cs:line 23
   at ThriveLauncher.Views.MainWindow..ctor() in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Views/MainWindow.axaml.cs:line 11
   at ThriveLauncher.App.OnFrameworkInitializationCompleted() in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/App.axaml.cs:line 28
   at Avalonia.Controls.AppBuilderBase`1.Setup() in /_/src/Avalonia.Controls/AppBuilderBase.cs:line 312
   at Avalonia.Controls.AppBuilderBase`1.SetupWithLifetime(IApplicationLifetime lifetime) in /_/src/Avalonia.Controls/AppBuilderBase.cs:line 179
   at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime[T](T builder, String[] args, ShutdownMode shutdownMode) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 208
   at ThriveLauncher.Program.Main(String[] args) in /home/hhyyrylainen/Projects/Thrive-Launcher/ThriveLauncher/Program.cs:line 15

Which is maybe why the transform animator is not hooked up by default...

Expected behavior
I expect that it would be easy to animate the render transform to make controls move around. For example to make a popup alert appear in a much more pleasing way.
I also tried animating RenderTransformOrigin which did nothing with <Setter Property="RenderTransformOrigin" Value="0,-500"/>, that didn't even bother crashing.

I got an opacity value to fade in nicely using the same approach but when I do the same thing with RenderTransform it crashes.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Fedora 36
  • Version 0.10.14

Additional context
I got the impression that this should work based on reading these documentation pages:

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions