Windows 8 – Animation d’une propriété personnalisée dans code-behind

En gros, je veux créer des formes et les animer. Alors je suis venu avec la classe personnalisée suivante:

public class FunkyShape : DependencyObject { public double Animator { get { return (double)GetValue(AnimatorProperty); } set { SetValue(AnimatorProperty, value); } } public static readonly DependencyProperty AnimatorProperty = DependencyProperty.Register("Animator", typeof(double), typeof(FunkyShape), new PropertyMetadata(0, new PropertyChangedCallback(Animator_Changed))); private static void Animator_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) { double delta = (double)e.NewValue - (double)e.OldValue; ((FunkyShape)d).ProcessDelta((double)e.NewValue, delta); } private void ProcessDelta(double val, double delta) { Holder.Width = val; Holder.Height = val; // Keep shape centered HolderPosition.X = delta / 2; HolderPosition.Y = delta / 2; } private Shape Holder; public TranslateTransform HolderPosition { get { return (TranslateTransform)Holder.RenderTransform; } } public FunkyShape(Canvas playground, Shape shapeToInit) { Holder = shapeToInit; Holder.Width = 10; Holder.Height = 10; Holder.Fill = new SolidColorBrush(Colors.Blue); Holder.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center; Holder.RenderTransform = new TranslateTransform() { X = 500, Y = 500 }; Holder.RenderTransformOrigin = new Point(0.5, 0.5); // init done playground.Children.Add(Holder); Animate(); } public void Animate() { DoubleAnimation g1 = GrowAnimation(); Storyboard sb = new Storyboard(); Storyboard.SetTarget(g1, this); // CAN'T FIND ANIMATOR PROPERTY Storyboard.SetTargetProperty(g1, "Animator"); sb.Children.Add(g1); sb.Begin(); // THROWS EXCEPTION } private static DoubleAnimation GrowAnimation() { DoubleAnimation growAnimation = new DoubleAnimation(); growAnimation.Duration = TimeSpan.FromMilliseconds(3000); growAnimation.From = 0; growAnimation.To = 100; growAnimation.AutoReverse = true; growAnimation.EnableDependentAnimation = true; growAnimation.RepeatBehavior = new RepeatBehavior(5); return growAnimation; } } 

Cependant, lorsque j’essaie de créer une instance de la classe et de l’append au canevas, j’obtiens Exception – Storyboard.Being () et la renvoie pour m’indiquer qu’elle ne trouve pas la propriété Animator.

Alors, qu’est-ce que je fais mal?

EDIT: Après 3 changements de code – il ne fonctionne toujours pas; J’ai l’erreur “Impossible de résoudre TargetProperty Animator sur un object spécifié”. Donc, si quelqu’un connaît la réponse – aidez-nous en modifiant le code. Merci!

EDIT: OK, après 24 heures de frappe violente contre le mur, certains progrès ont été accomplis: si j’ajoute une forme via XAML, cela l’anime, mais si je l’ajoute via du code situé derrière (Canvas.Children.Add), cela ne fonctionne pas. Laissez-moi voir si je peux comprendre pourquoi.

D’ACCORD,

J’ai trouvé la solution de contournement pour ce qui est évidemment un bogue dans le cadre (bien que je sois certain qu’un employé de MS publiera une réponse et dira que c’est une fonctionnalité / c’est-à-dire par sa conception). Plusieurs choses doivent être faites:

  1. Ajouter un constructeur par défaut / sans paramètre
  2. Changez la classe de base de FunkyShape en UserControl.
  3. Ouvrez la vue XAML de la classe Page à laquelle vous souhaitez append des formes.
  4. Ajoutez une instance de FunkyShape en tant qu’enfant dans Canvas XAML ( par exemple). CELA NE FONCTIONNERA PAS SANS CELA.
  5. Créez une instance de FunkyShape dans code-behind, ajoutez-la à la canvas, démarrez l’animation et amusez-vous à la voir fonctionner
  6. Basculez vers une technologie moins boguée.

Sous Windows 8, vous ne pouvez pas animer des propriétés personnalisées sans définir également la propriété enabledependentanimation sur true. En effet, les animations non déterministes sont désactivées par défaut.

Référence: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.animation.pointanimation.enabledependentanimation.aspx

Oui, vous devez définir cette propriété en tant que propriété de dépendance et pas seulement en tant que propriété CLR standard. Cela implique un peu de code de plaque de chaudière simple. Voir donc l’article du blog pour un exemple complet:

http://timheuer.com/blog/archive/2012/03/07/creating-custom-controls-for-metro-style-apps.aspx

D’accord, j’ai eu ce problème aussi, mais je ne voulais pas inclure un constructeur public sans paramètre dans ma classe, alors j’ai trouvé un autre moyen.

En gros, le problème est que WinRT est une plate-forme native et qu’il ne peut pas réfléchir au code .NET. C’est pourquoi le processus de construction des applications WinRT génère des métadonnées sur les types utilisés dans XAML (vous pouvez trouver le code approprié dans obj/(Debug|Release)/XamlTypeInfo.g.cs ).

Si un type n’est jamais utilisé dans XAML, aucune métadonnée concernant ce type n’est générée, ce qui signifie (entre autres) qu’il est impossible d’animer les propriétés du type.

Si vous écrivez une bibliothèque de classes, vous pouvez simplement inclure un dictionnaire de ressources XAML et déclarer une instance factice du type; des métadonnées seront générées. Cependant, il faut que le type ait un constructeur public sans paramètre, ce qui peut ne pas être souhaitable.

Il existe donc une autre solution: fournissez vous-même les métadonnées. Il y a plusieurs interfaces à implémenter, et ils ont beaucoup de membres, ce qui peut être assez fastidieux à faire manuellement. Heureusement, vous n’avez pas à le faire! Voici ce que vous pouvez faire:

  • append un constructeur public sans paramètre à la classe (temporairement)
  • créer un ResourceDictionary XAML et déclarer une instance de la classe qu’il contient (comme décrit ci-dessus)
  • copiez le fichier XamlTypeInfo.g.cs dans votre projet (je l’ai renommé XamlTypeInfo.cs )
  • remplace l’appel au constructeur par la throw new NotImplementedException()
  • supprimer le fichier ResourceDictionary
  • supprimer le constructeur public sans paramètre

Et vous avez terminé, l’animation fonctionne maintenant correctement.

Le processus est encore assez fastidieux, alors ce serait bien d’avoir un outil pour faire le travail pour nous …


EDIT: solution beaucoup plus simple: appliquez l’atsortingbut [Bindable] à la classe. Cela permet au générateur de métadonnées de prendre en compte le type même s’il n’est pas utilisé dans XAML. (ignorez le fait que la doc dit que c’est pour les types C ++; cela fonctionne aussi très bien sur les classes C #)