2009-07-13 9 views
6

Questa è una situazione che si presenta spesso:Qual è il modo migliore per avviare un'animazione quando cambia un valore associato?

Nella vista, si dispone di un controllo associato a una proprietà ViewModel (supportata da un valore INotifyPropertyChanged). Ad esempio:

<TextBlock Text="{Binding Path=Subtotal}"/> 

Quando la proprietà cambia, è necessario attirare l'attenzione dell'utente con alcune animazioni creative. Come posso utilizzare il fatto che la vista è già collegata alla notifica ed evitare di creare gran parte del codice aggiuntivo (o almeno crearlo una volta e riutilizzarlo). I trigger di dati sono probabilmente la scelta migliore, ma non so come farli sparare su qualsiasi variazione di valore rispetto ad un valore specifico.

le seguenti opzioni vengono in mente:

  • generare un evento aggiuntivo nel ViewModel, iscriviti nella Vista code-behind.
  • creare un datatrigger associato alla proprietà indicata utilizzando un convertitore che restituisce true se il valore sta cambiando.
  • creare un datatrigger associato a una nuova proprietà booleana sul ViewModel che viene utilizzato per "segnalare" la modifica.
  • crea un comportamento collegato al controllo che sottoscrive la modifica della proprietà di dipendenza del controllo e avvia l'animazione.

Quale preferisci? Ho perso qualche opzione?

P.S. Sarebbe bello (ma non critico) se la soluzione fornisse la possibilità di avviare prima l'animazione e riflettere il cambiamento di valore quando è terminata.

risposta

3

Ok, questo è quello che sono venuto dopo alcuni esperimenti.

Ho creato un trigger di Expression Blend 3 con una proprietà di dipendenza (l'ho chiamato Sottoscrizione). Mi legano l'abbonamento al medesimo valore che il mio TextBlock è legato a e questo trigger è collegata a un ControlStoryboardAction da Expression Blend 3.

Ecco il grilletto:

public class DataTriggerPlus : TriggerBase<DependencyObject> 
{ 
    public static readonly DependencyProperty SubscriptionProperty = 
     DependencyProperty.Register("Subscription", 
      typeof(string), 
      typeof(DataTriggerPlus), 
      new FrameworkPropertyMetadata("", 
       new PropertyChangedCallback(OnSubscriptionChanged))); 

    public string Subscription 
    { 
     get { return (string)GetValue(SubscriptionProperty); } 
     set { SetValue(SubscriptionProperty, value); } 
    } 

    private static void OnSubscriptionChanged(DependencyObject d, 
     DependencyPropertyChangedEventArgs e) 
    { 
     ((DataTriggerPlus)d).InvokeActions(null); 
    } 
} 

Ecco come è attaccato al storyboard :

<TextBlock x:Name="textBlock" Text="{Binding TestProp}" Background="White"> 
    <i:Interaction.Triggers> 
     <local:DataTriggerPlus Subscription="{Binding TestProp}"> 
      <im:ControlStoryboardAction 
       Storyboard="{StaticResource Storyboard1}"/> 
     </local:DataTriggerPlus> 
    </i:Interaction.Triggers> 
</TextBlock> 

mi piace questo approccio molto, grande lavoro Blend 3 progettisti!

Edit: rispondendo Drew commento ...

Sì, navi con Blend. Puoi semplicemente includere Microsoft.Expression.Interactions.dll e System.Windows.Interactivity nel tuo progetto.

E sì, è prolisso (ho chiesto se qualcuno ha trovato un buon modo per applicare i comportamenti tramite Stili in this question) - ma c'è anche un vantaggio di flessibilità. Ad esempio non puoi solo iniziare uno storyboard, ma anche cambiare uno stato o fare qualche altra azione dallo stesso trigger.

+1

Da dove proviene ''? Immagino che venga spedito con Blend. È disponibile per noi utenti non Blend? Voglio ottenere la stessa cosa nel mio codice, anche se spero che esista una soluzione meno verbosa in quanto ho molte istanze che richiedono questo. Forse è possibile tramite uno stile ... –

2

È possibile creare un trigger che avvierà l'animazione.

Qualcosa di simile a questo:

<Style> 
    <Style.Triggers> 
     <Trigger 
      Property="ViewModelProperty" 
      Value="True"> 
      <Trigger.EnterActions> 
       <BeginStoryboard Storyboard="YourStoryBoard" /> 
      </Trigger.EnterActions> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

quanto riguarda la questione per il rilascio di impostare il valore di una volta completata l'animazione, questo è un po 'di dolore. Per quanto ne so, avresti bisogno di usare l'evento completato sullo storyboard, questo richiede un codice nascosto, che è qualcosa che vuoi evitare con MVVM.

Ho provato ad utilizzare EventTriggers per associare gli eventi completati, ma questo introduce anche alcune complicazioni. Vedi here per maggiori dettagli.

+0

Ancora, cosa succede se la proprietà non è booleana o un insieme di scelte, ma una stringa o un numero arbitrario? –

+0

Quindi si utilizzerà un ValueConverter. Stessa soluzione, solo con un valore Convertitore –

+0

In che modo un convertitore di valori sa che il valore è stato modificato, a meno che non sia stato creato un convertitore di valori per ogni singolo legame? –

Problemi correlati