Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 35 di 59
  • livello principiante
Indice lezioni

Storyboard: gestire le animazioni

Impostare azioni e tempi delle animazioni dell'interfaccia
Impostare azioni e tempi delle animazioni dell'interfaccia
Link copiato negli appunti

Storyboard è l'oggetto che gestisce il ciclo di vita di una animazione. Come abbiamo già visto nelle precedenti lezioni, il suo utilizzo principale è quello di avviare l'animazione. Esiste però un altro modo, oltre all'invocazione del metodo Begin, per eseguire uno Storyboard ed è tramite l'uso di EventTrigger con l'elemento BeginStoryboard.

La differenza sostanziale sta nel fatto che il primo metodo lo possiamo utilizzare via codice procedurale (per esempio C#), mentre il secondo possiamo sfruttarlo direttamente nel codice XAML. Prima di vedere un esempio di quest'ultimo spieghiamo cos'è un EventTrigger, è un elemento che incapsula una porzione di codice XAML che viene attivata solo al verificarsi di un determinato RoutedEvent.

La sintassi è molto semplice, basta definirlo come elemento figlio della proprietà Triggers di un controllo e settare l'attributo RoutedEvent.

<Rectangle ...>
  <Rectangle.Triggers>
    <EventTrigger RoutedEvent="Rectangle.Loaded">
      ...
    </EventTrigger>
  </Rectangle.Triggers>
</Rectangle>

Gli EventTrigger hanno una grossa limitazione, dato che al momento l'unico evento supportato è Loaded. Sfruttando questo meccanismo possiamo eseguire un'animazione al verificarsi dell'evento Loaded, basta inserire una Storyboard racchiusa in un elemento BeginStoryboard. Vediamo un esempio completo.

<Canvas x:Name="LayoutRoot" Background="Azure">
  <Rectangle x:Name="MyRectangle" Canvas.Left="25" Canvas.Top="40" 
               Fill="Orange">
    <Rectangle.Triggers>
      <EventTrigger RoutedEvent="Rectangle.Loaded">
        <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation From="100" To="300" Duration="0:0:3"
                             Storyboard.TargetName="MyRectangle"
                             Storyboard.TargetProperty="Width" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
    </Rectangle.Triggers>
  </Rectangle>
</Canvas>

Diversamente se controlliamo l'animazione da codice abbiamo a disposizione molte più possibilità, in pratica possiamo immaginare l'oggetto Storyboard come un player video, quindi eseguire su di esso le tipiche operazione di avvio (Begin), pausa (Pause), ripresa (Resume), interruzione (Stop) e tante altre.

Per dimostrare alcune di queste funzionalità partiamo dall'animazione precedente, impostiamo, per le proprietà To e Duration, valori più alti ed aggiungiamo sotto al rettangolo una serie di Button per eseguire, da codice C#, le attività descritte prima.

<Canvas x:Name="LayoutRoot" Background="Azure">
  <Canvas.Resources>
    <Storyboard x:Name="myStoryboard">
      <DoubleAnimation x:Name="myAnimation"
                       From="100" To="1000" Duration="0:0:10"
                       Storyboard.TargetName="myRectangle"
                       Storyboard.TargetProperty="Width" />
    </Storyboard>
  </Canvas.Resources>
  
  <StackPanel Canvas.Left="25" Canvas.Top="40">
    <Rectangle x:Name="myRectangle"   Fill="Orange" HorizontalAlignment="Left" />
    
    <StackPanel Margin="10" Orientation="Horizontal">
    
      <Button ... Click="myBeginButton_Click" />
      <Button ... Click="myPauseButton_Click" />
      <Button ... Click="myResumeButton_Click" />
      <Button ... Click="myStopButton_Click" />
      <Button ... Click="myMoveButton_Click" />
    </StackPanel>
  </StackPanel>
</Canvas>

Nel code-behind non dobbiamo far altro che invocare i rispettivi metodi dell'oggetto Storyboard.

private void myBeginButton_Click(object sender, RoutedEventArgs e)
{
  myStoryboard.Begin();
}

private void myPauseButton_Click(object sender, RoutedEventArgs e)
{
  myStoryboard.Pause();
}

private void myResumeButton_Click(object sender, RoutedEventArgs e)
{
  myStoryboard.Resume();
}

private void myStopButton_Click(object sender, RoutedEventArgs e)
{
  myStoryboard.Stop();
}

private void myMoveButton_Click(object sender, RoutedEventArgs e)
{
  myStoryboard.Begin();
  var seconds = myAnimation.Duration.TimeSpan.TotalSeconds / 2;
  myStoryboard.Seek(TimeSpan.FromSeconds(seconds));
}

Eseguendo l'applicazione il risultato sarà simile a quello visualizzato nell'immagine seguente, catturata durante l'animazione.

Figura 48. Animazione con controlli
Animazione con controlli

I primi metodi sono auto esplicativi, ma l'ultimo forse richiede un minimo di spiegazione. Tramite il metodo Seek possiamo posizionare l'animazione ad un determinato intervallo di tempo passatogli come parametro, di tipo TimeSpan. Nel codice, prima invochiamo il metodo Begin per essere sicuri che l'animazione sia già in esecuzione, dopo calcoliamo l'intervallo di tempo desiderato ed infine passiamo al metodo Seek un TimeSpan generato dai secondi calcolati.

Esiste un altro aspetto importante da trattare per quanto riguarda il ciclo di vita di un'animazione, infatti anche quando è conclusa di fatto continua ad essere attiva, nell'esempio precedente anche dopo dieci secondi l'animazione continua ad applicare il valore To alla proprietà Width del rettangolo, invece di tornare al suo valore originale.

Questo comportamento è definito dalla proprietà FillBehavior dell'oggetto Storyboard, la quale per default è impostata a HoldEnd. Se vogliamo che al termine dell'animazione venga ripristinato il valore originale, in questo caso della larghezza del rettangolo, dobbiamo fermare l'animazione, per farlo possiamo agire in due modi, il primo è impostando FillBehavior a Stop, l'altro invece prevede che siamo noi ad invocare esplicitamente il metodo Stop dello Storyboard quando l'animazione è conclusa, per farlo dobbiamo intercettare l'evento Completed, come nel prossimo esempio.

<Canvas ...>
  <Canvas.Resources>
    <Storyboard x:Name="myStoryboard" 
                Completed="myStoryboard_Completed">
      <DoubleAnimation ... />
    </Storyboard>
  </Canvas.Resources>
  ...
</Canvas>


private void myStoryboard_Completed(object sender, EventArgs e)
{
    myStoryboard.Stop();
}

Ti consigliamo anche