2012-10-15 13 views
7

Fondamentalmente, voglio creare un gruppo di forme e renderle animate. Così mi è venuta con le seguenti classe personalizzata:Windows 8 - Animazione di proprietà personalizzate nel code-behind

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

Tuttavia, quando provo fare un'istanza della classe e aggiungendolo alla tela, ottengo Eccezione - Storyboard.Being() genera e mi dice che impossibile trovare la proprietà Animator.

Quindi, cosa sto sbagliando?

MODIFICA: Dopo 3 modifiche al codice, non funziona ancora; Ottengo errore "Impossibile risolvere TargetProperty Animator su oggetto specificato". Quindi se qualcuno conosce la risposta, per favore aiutateci modificando il codice. Grazie!

EDIT: OK, dopo 24 ore di sbattere la testa contro il muro c'è qualche progresso - se aggiungo forma attraverso XAML si anima, ma se lo aggiungo con il codice dietro (Canvas.Children.Add), è non funziona Fammi vedere se riesco a capire perché.

+0

Questo è esattamente lo stesso problema Im fronte atm. Se trovi una soluzione, per favore postala qui, anch'io lo farò;) –

+1

Penso che questo sia correlato: http://www.charlespetzold.com/blog/2012/03/The-Animated-Pie-Slice-in- Windows-8.html – kape123

+0

Bene, questo articolo è correlato a questo http://blog.jerrynixon.com/2012/06/windows-8-animated-pie-slice.html –

risposta

6

OK,

ho trovato la soluzione per quello che è, ovviamente, un bug nel quadro (anche se sono sicuro che alcuni dei dipendenti MS pubblicherà risposta e dico che è una caratteristica/it-è- by-design). Molte cose devono essere fatte:

  1. add default/parametro-less costruttore
  2. classe Cambio base del FunkyShape a UserControl.
  3. Aprite visualizzazione XAML della classe Page in cui si desidera aggiungere forme
  4. Aggiungere un'istanza di FunkyShape come un bambino all'interno del XAML tela (tm <: FunkyShape/> per esempio). NON FUNZIONERÀ SENZA QUESTO.
  5. Crea un'istanza di FunkyShape in code-behind, aggiungilo a canvas, avvia l'animazione e divertiti a vederlo funzionante
  6. Passa alla tecnologia meno buggata.
+0

grazie mille, lo ha fatto per me! – thumbmunkeys

+0

L'aggiunta di un'istanza in XAML ha risolto il problema per me; grazie per il consiglio. Ma sfortunatamente non è una soluzione praticabile per me, perché in realtà non voglio un costruttore senza parametri sulla mia classe (non avrebbe alcun senso). Sospetto che funzioni perché il compilatore XAML genera alcuni metadati sui tipi utilizzati in XAML e lo storyboard richiede quei metadati. Ti farò sapere se trovo una soluzione migliore. –

+0

il passaggio 4 potrebbe essere correlato alla risposta di Tim Heuer all'indirizzo https://social.msdn.microsoft.com/Forums/windowsapps/en-US/5e42e6a1-740f-48b2-9908-09a474f9d413/error-converter-failed-to-convert- value-of-type-quando-type-è-derivati? forum = winappswithcsharp –

1

Sì, è necessario definire questa proprietà come una proprietà di dipendenza, non solo una normale proprietà CLR. Ciò comporta un bel po 'di codice semplice della piastra della caldaia. Vedi dunque blog Post per un esempio completo:

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

+0

Ho appena provato a registrarlo come DependencyProperty (codice aggiornato) e ottengo lo stesso errore – kape123

+0

Il percorso della proprietà è errato, l'oggetto di destinazione è un 'FunkyShape', come specificato in questa istruzione' Storyboard.SetTarget (g1, this); 'Quindi la proprietà target dovrebbe essere solo' Animator', 'Storyboard.SetTargetProperty (g1," Animator ");' - Inoltre, è necessario aggiungere un gestore all'evento modificato DependencyProperty per aggiornare l'interfaccia utente in quanto la proprietà di dipendenza è animato. – ColinE

+0

@ColinE: l'animazione non chiamerà il setter della proprietà, giusto? Ma chiamerebbe PropertyChangedCallback? –

3

In Windows 8 non si può animare le proprietà personalizzate senza impostare anche la proprietà enabledependentanimation su true. Questo perché le animazioni non deterministiche sono disabilitate di default.

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

+1

Come ho detto in chat, ho - growAnimation.EnableDependentAnimation = true; - Linea, quindi non è quello. – kape123

+1

Grazie mille, ha risolto il mio problema :) –

+0

@FlorianGl Puoi pubblicare la tua lezione? Perché ovviamente non sta funzionando per il mio? – kape123

1

OK, ho avuto anche questo problema, ma non volevo includere un costruttore publicless pubblico nella mia classe, quindi ho trovato un altro modo.

In sostanza, il problema è che WinRT è una piattaforma nativa e non può effettuare la riflessione su codice .NET. Ecco perché il processo di compilazione per le app WinRT genera metadati relativi ai tipi utilizzati in XAML (puoi trovare il codice rilevante in obj/(Debug|Release)/XamlTypeInfo.g.cs).

Se un tipo non viene mai utilizzato in XAML, non vengono generati metadati relativi a questo tipo, il che significa (tra le altre cose) che non è possibile animare le proprietà del tipo.

Se si sta scrivendo una libreria di classi, è possibile includere solo un dizionario di risorse XAML e dichiarare un'istanza fittizia del tipo; causerà la generazione di metadati. Tuttavia, richiede che il tipo abbia un costruttore pubblico senza parametri, che potrebbe non essere desiderabile.

Quindi c'è un'altra soluzione: fornire i metadati da soli. Ci sono diverse interfacce da implementare e hanno molti membri, quindi può essere piuttosto noioso da fare manualmente. Fortunatamente, non devi! Ecco cosa si può fare:

  • aggiungere un costruttore senza parametri pubblico alla classe (temporaneamente)
  • creare un XAML ResourceDictionary e dichiarare un'istanza della classe in esso (come descritto sopra)
  • copiare il XamlTypeInfo.g.cs il file nel vostro progetto (ho rinominato a XamlTypeInfo.cs)
  • sostituire la chiamata al costruttore con throw new NotImplementedException()
  • eliminare il file ResourceDictionary
  • rimuovere il costruttore pubblico senza parametri

E il gioco è fatto, l'animazione ora funziona correttamente.

Il processo è ancora abbastanza noioso, quindi sarebbe bello avere uno strumento per fare il lavoro per noi ...


EDIT: molto soluzione più semplice: applicare l'attributo [Bindable] al classe. Fa in modo che il generatore di metadati prenda in considerazione il tipo anche se non è usato in XAML. (ignora il fatto che il documento dice che è per i tipi C++, funziona bene anche per le classi C#)

Problemi correlati