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.

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top