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
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. –
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? –
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é. –