WPF: Animation de TranslateTransform à partir de code

J’ai un canevas WPF sur lequel je crée dynamicment des objects à partir de code. Ces objects sont transformés en définissant la propriété RenderTransform et une animation doit être appliquée à l’une de ces transformations. Actuellement, je ne parviens pas à animer les propriétés d’une transformation (bien qu’aucune exception ne soit levée et que l’animation semble s’exécuter – l’événement terminé est levé).

De plus, si le système d’animation est souligné, parfois l’événement Storyboard.Completed n’est jamais déclenché.

Tous les exemples que j’ai rencontrés animent les transformations de XAML. La documentation MSDN suggère que la propriété x: Name d’une transformation doit être définie pour que celle-ci puisse être animée, mais je n’ai pas trouvé de méthode efficace pour la définir à partir du code.

Des idées?

Voici la liste complète du code qui reproduit le problème:

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 { ///  /// Interaction logic for MainWindow.xaml ///  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  { 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()); } } } 

Laissez le storyboard:

 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); 

(petit correctif pour la syntaxe)

On dirait qu’après un peu de recherche sur Google, j’ai résolu le problème moi-même. Un grand merci à la documentation MSDN et à une publication dans les forums MSDN par Antares19 .

En résumé:

  • Pour qu’un object Freezable (comme TranslateTransform) puisse être ciblé par un Storyboard, il doit avoir un nom enregistré. Cela peut être fait en appelant FrameworkElement.RegisterName (..).

  • J’ai ajouté l’object Storyboard au ResourceDictionary du même élément de cadre auquel j’ai enregistré TranslateTransform. Cela peut être fait en appelant ResourceDictionary.Add (..)

Voici le code mis à jour, qui s’anime maintenant bien, et enregistre / désenregistre les ressources ajoutées:

 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()); } } } 

J’ai une solution utilisant XAML / C # Combo. Dans votre fichier XAML, définissez:

    

Cela vous permettra d’effectuer les opérations suivantes dans le code C #:

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

Le rest est comme d’habitude. Créez une DoubleAnimation, définissez ses propriétés, ajoutez-la en tant qu’enfant à votre Storyboard, appelez la fonction Commencer sur le story-board.