Qual è il modo migliore per iniziare un'animazione quando un balzo variazioni di valore?
-
13-09-2019 - |
Domanda
Questa è una situazione che si presenta spesso:
In vista, si dispone di un controllo associato a una proprietà ViewModel (sostenuta da un INotifyPropertyChanged). Ad esempio:
<TextBlock Text="{Binding Path=Subtotal}"/>
Quando i cambiamenti di proprietà, è necessario portare l'attenzione dell'utente sul fatto con un po 'di animazione creativa. Come posso utilizzare il fatto che la vista è già predisposto per la notifica ed evitare di creare la maggior parte del codice aggiuntivo (o almeno creare una volta e riutilizzo). trigger di dati sono probabilmente la scelta migliore, ma non so come farli incendio di uno qualsiasi modifica del valore rispetto a un valore specifico.
Le seguenti opzioni vengono in mente:
- generare un evento aggiuntivo nel ViewModel, iscriviti nella Vista code-behind.
- creare un DataTrigger destinata a beni di cui si utilizza un convertitore che restituisca true se il valore sta cambiando.
- creare un DataTrigger legato ad una nuova proprietà booleana sul ViewModel che viene utilizzato per "segnale" il cambiamento.
- creare un comportamento collegato al controllo che iscriversi alla modifica della proprietà di dipendenza del controllo e avviare l'animazione.
Quale ti piace / usa? Mi sono perso nessuna opzione?
P.S. Sarebbe bello (ma non critico) se la soluzione fornirebbe la possibilità di avviare l'animazione prima e riflettono la variazione di valore quando è finita.
Soluzione
Ok, questo è quello che mi è venuto a dopo qualche esperimento.
Ho creato un Expression Blend 3 grilletto con una proprietà di dipendenza (ho chiamato abbonamento). Mi legano l'abbonamento al medesimo valore che il mio TextBlock è legato a questo trigger ed è attaccato ad una 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!
Modifica: rispondendo Drew commento ...
Sì, le navi con Blend. Si può solo includere Microsoft.Expression.Interactions.dll e System.Windows.Interactivity nel progetto.
E sì, è prolisso (ho chiesto se qualcuno capito un buon modo per applicare comportamenti tramite Styles in questa domanda ) - ma c'è anche un vantaggio di flessibilità. Per esempio non si può solo iniziare una storyboard, ma anche passare uno stato o fare qualche altra azione dallo stesso grilletto.
Altri suggerimenti
È possibile creare un trigger che inizierà 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>
Per quanto riguarda il problema per il rilascio di impostare il valore di una volta completata l'animazione, questo è un po 'di dolore. Per quanto io sappia avresti bisogno di utilizzare l'evento completato sullo storyboard, questo richiede codice alla base, che è qualcosa che si vuole evitare con MVVM.
Ho provato con Eventtriggers di legarsi agli eventi terminati, ma che introduce anche alcune complicazioni. Vedi qui per ulteriori dettagli.