J'ai besoin d'aide pour prendre la bonne décision. J'ai besoin d'animer une couleur d'arrière-plan de mon contrôle utilisateur lorsqu'un événement se produit. Lorsque cela se produit, je souhaite modifier l'arrière-plan pendant une seconde, puis le rétablir. Dans quel sens devrais-je aller? Utilisez une animation couleur ou une minuterie ou peut-être d'une autre manière.
Résolu. Merci à tous! Cela fonctionne bien pour moi:
ColorAnimation animation;
animation = new ColorAnimation();
animation.From = Colors.Orange;
animation.To = Colors.Gray;
animation.Duration = new Duration(TimeSpan.FromSeconds(1));
this.elGrid.Background.BeginAnimation(SolidColorBrush.ColorProperty, animation);
J'utiliserais une EventTrigger
avec une ColorAnimation
.
Dans cet exemple, un Button Brackground
devient vert sur un événement MouseLeave
. Espérons que ce code est similaire à ce dont vous pourriez avoir besoin.
<Button Content="Button" Height="75" HorizontalAlignment="Left" Margin="27,12,0,0" Name="btnImgBrush" VerticalAlignment="Top" Width="160" Background="LightGray">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation To="Green"
Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)"
FillBehavior="Stop"
Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Attention, vous pourriez recevoir une exception System.InvalidOperationException si votre arrière-plan est une instance gelée.
Impossible d'animer la propriété 'Color' sur 'System.Windows.Media.SolidColorBrush' car l'objet est scellé ou gelé.
Pour corriger ce message, affectez l’arrière-plan de votre contrôle à une instance non gelée.
// Do not use a frozen instance
this.elGrid.Background = new SolidColorBrush(Colors.Orange);
this.elGrid.Background.BeginAnimation(SolidColorBrush.ColorProperty, animation);
ColorAnimation colorChangeAnimation = new ColorAnimation();
colorChangeAnimation.From = VariableColour;
colorChangeAnimation.To = BaseColour;
colorChangeAnimation.Duration = timeSpan;
PropertyPath colorTargetPath = new PropertyPath("(Panel.Background).(SolidColorBrush.Color)");
Storyboard CellBackgroundChangeStory = new Storyboard();
Storyboard.SetTarget(colorChangeAnimation, BackGroundCellGrid);
Storyboard.SetTargetProperty(colorChangeAnimation, colorTargetPath);
CellBackgroundChangeStory.Children.Add(colorChangeAnimation);
CellBackgroundChangeStory.Begin();
// VariableColour & BaseColour sont une classe de Color, timeSpan est une classe de TimeSpan, BackGroundCellGrid est une classe de grille.
// pas besoin de créer SolidColorBrush et de le lier en XAML; //s'amuser!
Voici un ensemble de propriétés attachées qui peuvent être utilisées si vous rencontrez des problèmes avec des objets gelables.
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
public static class Blink
{
public static readonly DependencyProperty WhenProperty = DependencyProperty.RegisterAttached(
"When",
typeof(bool?),
typeof(Blink),
new PropertyMetadata(false, OnWhenChanged));
public static readonly DependencyProperty FromProperty = DependencyProperty.RegisterAttached(
"From",
typeof(Color),
typeof(Blink),
new FrameworkPropertyMetadata(Colors.Transparent, FrameworkPropertyMetadataOptions.Inherits));
public static readonly DependencyProperty ToProperty = DependencyProperty.RegisterAttached(
"To",
typeof(Color),
typeof(Blink),
new FrameworkPropertyMetadata(Colors.Orange, FrameworkPropertyMetadataOptions.Inherits));
public static readonly DependencyProperty PropertyProperty = DependencyProperty.RegisterAttached(
"Property",
typeof(DependencyProperty),
typeof(Blink),
new PropertyMetadata(default(DependencyProperty)));
public static readonly DependencyProperty DurationProperty = DependencyProperty.RegisterAttached(
"Duration",
typeof(Duration),
typeof(Blink),
new PropertyMetadata(new Duration(TimeSpan.FromSeconds(1))));
public static readonly DependencyProperty AutoReverseProperty = DependencyProperty.RegisterAttached(
"AutoReverse",
typeof(bool),
typeof(Blink),
new PropertyMetadata(true));
public static readonly DependencyProperty RepeatBehaviorProperty = DependencyProperty.RegisterAttached(
"RepeatBehavior",
typeof(RepeatBehavior),
typeof(Blink),
new PropertyMetadata(RepeatBehavior.Forever));
private static readonly DependencyProperty OldBrushProperty = DependencyProperty.RegisterAttached(
"OldBrush",
typeof(Brush),
typeof(Blink),
new PropertyMetadata(null));
public static void SetWhen(this UIElement element, bool? value)
{
element.SetValue(WhenProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static bool? GetWhen(this UIElement element)
{
return (bool?)element.GetValue(WhenProperty);
}
public static void SetFrom(this DependencyObject element, Color value)
{
element.SetValue(FromProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static Color GetFrom(this DependencyObject element)
{
return (Color)element.GetValue(FromProperty);
}
public static void SetTo(this DependencyObject element, Color value)
{
element.SetValue(ToProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static Color GetTo(this DependencyObject element)
{
return (Color)element.GetValue(ToProperty);
}
public static void SetProperty(this UIElement element, DependencyProperty value)
{
element.SetValue(PropertyProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static DependencyProperty GetProperty(this UIElement element)
{
return (DependencyProperty)element.GetValue(PropertyProperty);
}
public static void SetDuration(this UIElement element, Duration value)
{
element.SetValue(DurationProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static Duration GetDuration(this UIElement element)
{
return (Duration)element.GetValue(DurationProperty);
}
public static void SetAutoReverse(this UIElement element, bool value)
{
element.SetValue(AutoReverseProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static bool GetAutoReverse(this UIElement element)
{
return (bool)element.GetValue(AutoReverseProperty);
}
public static void SetRepeatBehavior(this UIElement element, RepeatBehavior value)
{
element.SetValue(RepeatBehaviorProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(UIElement))]
public static RepeatBehavior GetRepeatBehavior(this UIElement element)
{
return (RepeatBehavior)element.GetValue(RepeatBehaviorProperty);
}
private static void OnWhenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var property = GetProperty((UIElement)d) ?? GetDefaultProperty(d);
if (property == null || !typeof(Brush).IsAssignableFrom(property.PropertyType))
{
if (DesignerProperties.GetIsInDesignMode(d))
{
if (property != null)
{
throw new ArgumentException($"Could not blink for {d.GetType().Name}.{property.Name}", nameof(d));
}
}
return;
}
AnimateBlink(e.NewValue as bool?, (UIElement)d, property);
}
private static DependencyProperty GetDefaultProperty(DependencyObject d)
{
if (d is Control)
{
return Control.BackgroundProperty;
}
if (d is Panel)
{
return Panel.BackgroundProperty;
}
if (d is Border)
{
return Border.BackgroundProperty;
}
if (d is Shape)
{
return Shape.FillProperty;
}
if (DesignerProperties.GetIsInDesignMode(d))
{
throw new ArgumentException($"Could not find property to blink for {d.GetType().Name}", nameof(d));
}
return null;
}
private static void AnimateBlink(bool? blink, UIElement element, DependencyProperty property)
{
if (element == null)
{
return;
}
if (blink == true)
{
var brush = element.GetValue(property);
element.SetCurrentValue(OldBrushProperty, brush);
element.SetValue(property, Brushes.Transparent);
var from = element.GetFrom();
var to = element.GetTo();
var sb = new Storyboard();
var duration = element.GetDuration();
var animation = new ColorAnimation(from, to, duration)
{
AutoReverse = element.GetAutoReverse(),
RepeatBehavior = element.GetRepeatBehavior()
};
Storyboard.SetTarget(animation, element);
Storyboard.SetTargetProperty(animation, new PropertyPath($"{property.Name}.(SolidColorBrush.Color)"));
sb.Children.Add(animation);
sb.Begin();
}
else
{
var brush = element.GetValue(OldBrushProperty);
element.BeginAnimation(property, null);
element.SetCurrentValue(property, brush);
}
}
}
Usage:
<Grid>
<Grid.Resources>
<Style x:Key="BlinkWhenMouseOver"
TargetType="{x:Type Border}">
<Setter Property="local:Blink.When" Value="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" />
<Setter Property="local:Blink.From" Value="Honeydew" />
<Setter Property="local:Blink.To" Value="HotPink" />
<Setter Property="BorderThickness" Value="5" />
<Setter Property="local:Blink.Property" Value="{x:Static Border.BorderBrushProperty}" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Border Style="{StaticResource BlinkWhenMouseOver}" Background="Transparent"/>
<Border Grid.Row="1"
local:Blink.From="Aqua"
local:Blink.To="Yellow"
local:Blink.When="{Binding IsChecked,
ElementName=ToggleBlink}" />
<ToggleButton x:Name="ToggleBlink"
Grid.Row="2"
Content="Blink" />
</Grid>
Ce post m'a aidé. Mais s'il s'agit de changer la couleur après 1 seconde, comme le dit la question initiale,
ColorAnimation animation;
animation = new ColorAnimation();
animation.AutoReverse =true;
Dans WPF, utiliser l'animation peut-être mieux. Le mélange d'expression a l'animation/le comportement relatif.
Cela a bien fonctionné pour moi.
J'ai un chemin à l'intérieur d'un bouton (il dessine un "X"):
<Path x:Name="MyDeleteRowButton" Stroke="Gray" Grid.Row="0"
Data="M1,5 L11,15 M1,15 L11,5" StrokeThickness="2" HorizontalAlignment="Center"
Stretch="None"/>
Au passage de la souris, je veux que la croix devienne rouge, alors j'ajoute:
<DataTemplate.Triggers>
<!-- Highlight row on mouse over, and highlight the delete button. -->
<EventTrigger RoutedEvent="ItemsControl.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<!-- On mouse over, flicker the row to highlight it.-->
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="0.5"
To="1"
Duration="0:0:0.250"
FillBehavior="Stop"/>
<!-- Highlight the delete button with red. -->
<ColorAnimation
To="Red"
Storyboard.TargetName="MyDeleteRowButton"
Storyboard.TargetProperty="(Stroke).(SolidColorBrush.Color)"
Duration="0:0:0.100"
FillBehavior="HoldEnd"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<!-- Grey out the delete button. -->
<EventTrigger RoutedEvent="ItemsControl.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<!-- Space is precious: "delete" button appears only on a mouseover. -->
<ColorAnimation
To="Gray"
Storyboard.TargetName="MyDeleteRowButton"
Storyboard.TargetProperty="(Stroke).(SolidColorBrush.Color)"
Duration="0:0:0.100"
FillBehavior="HoldEnd"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</DataTemplate.Triggers>
La chose la plus déroutante à ce sujet est les crochets dans Storyboard.TargetProperty
. Si vous supprimez les crochets, rien ne fonctionne.
Pour plus d'informations, voir " propertyName Grammar " et " Storyboard.TargetProperty ".