WPF: анимация TranslateTransform из кода

У меня есть WPF-холст, на котором я динамически создаю объекты из кода. Эти объекты преобразуются путем установки свойства RenderTransform, и анимация должна быть применена к одному из этих преобразований. В настоящее время я не могу получить свойства какого-либо преобразования для анимации (хотя исключение не возникает, и анимация, как представляется, запускается - завершенное событие увеличивается).

Кроме того, если система анимации подчеркнута, иногда событие Storyboard.Completed никогда не поднимается.

Все примеры, которые я придумал, преобразуют преобразования из XAML. Документация MSDN предполагает, что свойство x: Name преобразования должно быть установлено для его анимации, но я не нашел рабочего пути для установите его из кода.

Любые идеи?

Здесь полный список кодов, который воспроизводит проблему:

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace AnimationCompletedTest {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {

        Canvas panel;
        public MainWindow() {
            InitializeComponent();
            MouseDown += DoDynamicAnimation;

            Content = panel = new Canvas();
        }

        void DoDynamicAnimation(object sender, MouseButtonEventArgs args) {

            for (int i = 0; i < 12; ++i) {
                var e = new Ellipse {
                    Width = 16,
                    Height = 16,
                    Fill = SystemColors.HighlightBrush
                };
                Canvas.SetLeft(e, Mouse.GetPosition(this).X);
                Canvas.SetTop(e, Mouse.GetPosition(this).Y);

                var tg = new TransformGroup();
                var translation = new TranslateTransform(30, 0);
                tg.Children.Add(translation);
                tg.Children.Add(new RotateTransform(i * 30));
                e.RenderTransform = tg;

                panel.Children.Add(e);

                var s = new Storyboard();
                Storyboard.SetTarget(s, translation);
                Storyboard.SetTargetProperty(s, new PropertyPath(TranslateTransform.XProperty));

                s.Children.Add(
                    new DoubleAnimation(3, 100, new Duration(new TimeSpan(0, 0, 0, 1, 0))) {
                        EasingFunction = new PowerEase {EasingMode = EasingMode.EaseOut}
                    });

                s.Completed += 
                    (sndr, evtArgs) => {
                        Debug.WriteLine("Animation {0} completed {1}", s.GetHashCode(), Stopwatch.GetTimestamp());
                        panel.Children.Remove(e);
                    };

                Debug.WriteLine("Animation {0} started {1}", s.GetHashCode(), Stopwatch.GetTimestamp());

                s.Begin();
            }
        }

        [STAThread]
        public static void Main() {
            var app = new Application();
            app.Run(new MainWindow());
        }
    }
}

Ответы

Ответ 1

Кажется, что после немногого Googling я сам решил проблему. Большое спасибо документация MSDN и сообщение в форумах MSDN от Antares19.

Вкратце:

  • Для объекта Freezable (например, TranslateTransform), который должен быть настроен на раскадровку, он должен иметь зарегистрированное имя. Это можно сделать, вызвав FrameworkElement.RegisterName(..).

  • Я добавил объект Storyboard в ResourceDictionary того же элемента Framework, на который я зарегистрировал TranslateTransform. Это можно сделать, вызвав ResourceDictionary.Add(..)

Здесь обновленный код, который теперь хорошо анимируется, и регистрирует/отменяет добавление дополнительных ресурсов:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace AnimationCompletedTest {

    public partial class MainWindow : Window {

        Canvas panel;
        public MainWindow() {
            InitializeComponent();
            MouseDown += DoDynamicAnimation;

            Content = panel = new Canvas();
        }

        void DoDynamicAnimation(object sender, MouseButtonEventArgs args) {
            for (int i = 0; i < 12; ++i) {
                var e = new Ellipse { Width = 16, Height = 16, Fill = SystemColors.HighlightBrush };
                Canvas.SetLeft(e, Mouse.GetPosition(this).X);
                Canvas.SetTop(e, Mouse.GetPosition(this).Y);

                var tg = new TransformGroup();
                var translation = new TranslateTransform(30, 0);
                var translationName = "myTranslation" + translation.GetHashCode();
                RegisterName(translationName, translation);
                tg.Children.Add(translation);
                tg.Children.Add(new RotateTransform(i * 30));
                e.RenderTransform = tg;

                panel.Children.Add(e);

                var anim = new DoubleAnimation(3, 100, new Duration(new TimeSpan(0, 0, 0, 1, 0))) {
                    EasingFunction = new PowerEase { EasingMode = EasingMode.EaseOut }
                };

                var s = new Storyboard();
                Storyboard.SetTargetName(s, translationName);
                Storyboard.SetTargetProperty(s, new PropertyPath(TranslateTransform.YProperty));
                var storyboardName = "s" + s.GetHashCode();
                Resources.Add(storyboardName, s);

                s.Children.Add(anim);

                s.Completed +=
                    (sndr, evtArgs) => {
                        panel.Children.Remove(e);
                        Resources.Remove(storyboardName);
                        UnregisterName(translationName);
                    };
                s.Begin();
            }
        }

        [STAThread]
        public static void Main() {
            var app = new Application();
            app.Run(new MainWindow());
        }
    }
}

Ответ 2

Оставь Раскадку:

var T = new TranslateTransform(40, 0);
Duration duration = new Duration(new TimeSpan(0, 0, 0, 1, 0));
DoubleAnimation anim = new DoubleAnimation(30, duration);
T.BeginAnimation(TranslateTransform.YProperty, anim);

(небольшое исправление для синтаксиса)

Ответ 3

У меня есть решение с помощью XAML/С# Combo. В файле XAML определите:

<UserControl.RenderTransform>
    <TranslateTransform x:Name="panelTrans" Y="0"></TranslateTransform>
</UserControl.RenderTransform>

Это даст вам возможность сделать следующее в коде С#:

        Storyboard.SetTargetName(mFlyInDA, "panelTrans");
        Storyboard.SetTargetProperty(mFlyInDA, new PropertyPath("Y"));

Остальное - это как обычно. Создайте DoubleAnimation, установите его свойства, добавьте его в качестве ребенка на свою раскадровку, вызовите функцию "Начало" на панели рассказов.