2016-06-14 2 views
0

Je souhaite exécuter une animation simple sur une image en forme de flèche (png). La flèche pointe vers le bas ou vers le haut, et l'animation est censée être une vague qui traverse la flèche dans la direction vers laquelle elle pointe. J'utilise le contrôle Image et lui assigne un des deux styles. Ces styles définissent l'image à utiliser et trois animations doubles dans un storyboard. L'animation est censée se dérouler sans condition, juste à partir du moment où l'image est créée, pour toujours. L'un des styles est une flèche pointant vers le haut avec une vague se déplaçant vers le haut (Trend_Rising), et l'autre style est une flèche pointant vers le bas avec une vague qui descend (Trend_Falling).Storyboard ne change pas lorsque je change de style dans WPF

Voici l'image et le style est dans un fichier distinct référencé à partir de UserControl où l'image est incorporée.

<Image x:Name="TrendImg" Style="{DynamicResource Trend_Falling}" /> 

Ceci est le contenu du fichier de styles:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 

    <Style x:Key="Trend_Base" TargetType="Image"> 

     <Setter Property="OpacityMask"> 
      <Setter.Value> 
       <LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> 
        <GradientStop Color="Black" /> 
        <GradientStop Color="Transparent" /> 
        <GradientStop Color="Black" /> 
       </LinearGradientBrush> 
      </Setter.Value> 
     </Setter> 

    </Style> 

    <Style x:Key="Trend_Rising_Base" TargetType="Image" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="IsVisible" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0" To="1.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1" To="1.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Falling_Base" TargetType="Image" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="IsVisible" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Rising" TargetType="Image" BasedOn="{StaticResource Trend_Rising_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_rising.png" /> 
    </Style> 

    <Style x:Key="Trend_Falling" TargetType="Image" BasedOn="{StaticResource Trend_Falling_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_falling.png" /> 
    </Style> 

</ResourceDictionary> 

La chose est que quand je change le style par programmation, l'animation ne change pas. Par exemple, si je lance l'application (l'image a le style Trend_Falling assigné), la flèche vers le bas sera affichée avec l'animation des vagues se déplaçant vers le bas comme il se doit. Mais quand je change le style en Trend_Rising à l'exécution, l'image de la flèche change comme il se doit, mais l'animation reste la même.

TrendImg.SetResourceReference(Control.StyleProperty, "Trend_Rising") 

Qu'est-ce que je fais mal? Je serai reconnaissant pour toute aide. Je vous remercie!

- EDIT -

J'ai créé un ImageWithAnim classe qui est un descendant de l'image , et a ajouté un booléenne Animer propriété de dépendance à elle. Puis j'ai attaché le déclencheur à cette propriété au lieu de IsVisible. Vrai commence le storyboard et false est censé l'arrêter, mais il ne le fait pas ... Lorsque je mets Animer à false, une exception est levée disant que le nom RisingStoryboard ne peut pas être résolu dans l'espace de noms System.Windows .Style. J'ai trouvé plusieurs posts sur StackOverflow selon lesquels cet exemple devrait fonctionner (parmi ceux qui ont prétendu que ce ne sera pas :-)).

Alors ... maintenant, je n'ai aucune idée de comment le faire correctement. Je serai reconnaissant pour toute aide. Je vous remercie!

C'est le XAML changé:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Test="clr-namespace:StyleChangeTest"> 

    <Style x:Key="Trend_Base" TargetType="Test:ImageWithAnim"> 

     <Setter Property="OpacityMask"> 
      <Setter.Value> 
       <LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> 
        <GradientStop Color="Black" /> 
        <GradientStop Color="Transparent" /> 
        <GradientStop Color="Black" /> 
       </LinearGradientBrush> 
      </Setter.Value> 
     </Setter> 

    </Style> 

    <Style x:Key="Trend_Rising_Base" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="RisingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0" To="1.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1" To="1.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 

      <Trigger Property="Animate" Value="False"> 
       <Trigger.EnterActions> 
        <StopStoryboard BeginStoryboardName="RisingStoryboard" /> 
       </Trigger.EnterActions> 
      </Trigger> 
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Falling_Base" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="FallingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 
      </Trigger> 

      <Trigger Property="Animate" Value="False"> 
       <Trigger.EnterActions> 
        <StopStoryboard BeginStoryboardName="FallingStoryboard" /> 
       </Trigger.EnterActions> 
      </Trigger>     
     </Style.Triggers> 

    </Style> 

    <Style x:Key="Trend_Rising" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Rising_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_rising.png" /> 
    </Style> 

    <Style x:Key="Trend_Falling" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Falling_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_falling.png" /> 
    </Style> 

</ResourceDictionary> 

Et voici le ImageWithAnim classe:

Public Class ImageWithAnim 
    Inherits Image 

    Private Shared _animate As DependencyProperty = DependencyProperty.Register("Animate", 
                       GetType(Boolean), 
                       GetType(ImageWithAnim), 
                       New PropertyMetadata(defaultValue:=False)) 

    Public Shared ReadOnly Property AnimateProperty As DependencyProperty 
     Get 
      Return _animate 
     End Get 
    End Property 

    Public Property Animate() As Boolean 
     Get 
      Return CBool(GetValue(_animate)) 
     End Get 
     Set(value As Boolean) 
      SetValue(_animate, value) 
     End Set 
    End Property 

End Class 
+0

Vous ciblez uniquement un type de cible d'image. Donc ça ne fait rien que l'image elle-même ait changé, juste qu'il y ait une image. Si vous allez suivre cette route, lorsque vous changez la source d'image, vous devrez arrêter/démarrer manuellement entre les animations séparées. –

+0

Merci, @ChrisW., Mais comment arrêter l'animation et la redémarrer? Je connais WPF dans une certaine mesure, mais je ne suis pas un spécialiste. Peut-il être fait d'une manière simple en utilisant un style, ou devrait-il être fait par programme? La première idée qui me vient à l'esprit est de créer un descendant de classe Image avec une propriété qui détermine si l'animation doit démarrer ou s'arrêter. Utilisez ensuite cette classe au lieu de Image et attachez le déclencheur à cette propriété au lieu de IsVisible. Est-ce une bonne idée ou tout peut-il être fait plus simple? –

+0

J'ai créé un descendant de Image avec une propriété de dépendance Animate booléenne. Je l'ai utilisé dans le style au lieu de IsVisible et j'ai réussi à démarrer l'animation en mettant Animate à True. Toutefois, l'arrêter en définissant Animate sur False n'a pas fonctionné. J'ai donc ajouté un second déclencheur attaché à Animate = False avec un élément StopStoryboard qui avait BeginStoryBoardName défini sur le x: Nom du BeginStoryboard défini pour Animate = True. Maintenant, chaque fois que je définis Animate sur False, j'obtiens une exception disant que le nom BeginStoryboard spécifié ne peut pas être résolu dans l'espace de noms System.Windows.Style. Je suis coincé. –

Répondre

0

Par hasard, je viens de trouver une réponse à ma propre question. Les noms des storyboards n'ont pas pu être résolus car ils ont été définis dans les styles de base.Lorsque je les ai définis directement dans mes deux styles d'intérêt, je pourrais les démarrer et les arrêter en utilisant la propriété Animate de ImageWithAnim comme prévu, sans aucune exception.

Ainsi, lors du changement de style de l'image, je dois faire ce qui suit:

TrendImg.Animate = False 
TrendImg.SetResourceReference(ImageWithAnim.StyleProperty, "Trend_Falling") 
TrendImg.Animate = True 

Maintenant, l'animation est changé correctement, et l'animation d'onde se déplace dans la direction la flèche pointe vers, qui est ce que je voulais réaliser.

Et voici le style a changé:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Test="clr-namespace:StyleChangeTest"> 

    <Style x:Key="Trend_Base" TargetType="Test:ImageWithAnim"> 

     <Setter Property="OpacityMask"> 
      <Setter.Value> 
       <LinearGradientBrush StartPoint="0,1" EndPoint="0,0"> 
        <GradientStop Color="Black" /> 
        <GradientStop Color="Transparent" /> 
        <GradientStop Color="Black" /> 
       </LinearGradientBrush> 
      </Setter.Value> 
     </Setter> 

    </Style> 

    <Style x:Key="Trend_Rising" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_rising.png" /> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="RisingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0" To="1.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1" To="1.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 

       <Trigger.ExitActions> 
        <StopStoryboard BeginStoryboardName="RisingStoryboard" /> 
       </Trigger.ExitActions> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

    <Style x:Key="Trend_Falling" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}"> 
     <Setter Property="Height" Value="16" /> 
     <Setter Property="Source" Value="trend_falling.png" /> 

     <Style.Triggers> 
      <Trigger Property="Animate" Value="True"> 
       <Trigger.EnterActions> 
        <BeginStoryboard x:Name="FallingStoryboard"> 
         <Storyboard> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0" Duration="0:0:2" RepeatBehavior="Forever" /> 
          <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1" Duration="0:0:2" RepeatBehavior="Forever" /> 
         </Storyboard> 
        </BeginStoryboard> 
       </Trigger.EnterActions> 

       <Trigger.ExitActions> 
        <StopStoryboard BeginStoryboardName="FallingStoryboard" /> 
       </Trigger.ExitActions> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

</ResourceDictionary> 

Et d'expliquer pourquoi je mets les storyboards dans les styles de base au début. La chose est que dans mon application originale, j'ai plusieurs images de flèches différentes, et je ne voulais pas répéter les définitions de storyboard. Mais il semble que je dois le faire.