How to make button and background flash in wpf - c#

Issue
The issue I am having is when a user clicks a button I want the button to start flashing from 100% visible to around 20% visible and the background of the WPF window to change colors from #ffffff to #d6786a and this should happen untill the button is clicked again. Then the animations should stop.
Code
I have done a bit of diging around to find where somone has done this and I can't seem to see anything. The code i have at the moment is as follows.
Here is the button I want to flash from 100% visible to 20% visible when clicked:
<Button Name="button2" Style="{DynamicResource NoChromeButton}" Visibility="{Binding VisableState, Converter={StaticResource BoolToVis}}" ToolTip="Start Live Stream" Command="{Binding PlayStream}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="5" Height="22" Width="22" >
<Image Source="../Images/recordicon.png"/>
</Button>
I have tried to add a storyboard into the button and it just didn't work:
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard BeginTime="00:00:00"
RepeatBehavior="Forever"
Storyboard.TargetName="button2"
Storyboard.TargetProperty="(Visibility)">
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
I am new to WPF so going into animation is more difficult for me. If anyone could give me a little help on this stage it would be great.

Define animations in resources for example like this
<Window x:Name="window" x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Storyboard x:Key="FlashButton" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="button">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.2"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="ChangeColor">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="grid">
<EasingColorKeyFrame KeyTime="0:0:1" Value="Red"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="ChangeColor2">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="grid">
<EasingColorKeyFrame KeyTime="0:0:1" Value="White"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Grid x:Name="grid" Background="White">
<Button x:Name="button" Content="Button" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="75" Click="button_Click"/>
</Grid>
and create handler for button click
private bool isRunning;
private void button_Click(object sender, RoutedEventArgs e)
{
var flashButton = FindResource("FlashButton") as Storyboard;
var changeColor = FindResource("ChangeColor") as Storyboard;
var changeColor2 = FindResource("ChangeColor2") as Storyboard;
if (isRunning)
{
flashButton.Stop();
changeColor2.Begin();
isRunning = false;
}
else
{
flashButton.Begin();
changeColor.Begin();
isRunning = true;
}
}

To change "visibility to around 20%" you have to animate Opacity property (double type from 0.0 to 1.0) not Visibility (enum with 3 values, see msdn).
The goal can be easily achieved if you can use ToggleButton (because of its nice Checked and Unckecked routed events):
<ToggleButton>
<ToggleButton.Triggers>
<EventTrigger RoutedEvent="ToggleButton.Checked">
<BeginStoryboard x:Name="storyboard">
<Storyboard RepeatBehavior="Forever"
AutoReverse="True">
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="0.2"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ToggleButton.Unchecked">
<StopStoryboard BeginStoryboardName="storyboard" />
</EventTrigger>
</ToggleButton.Triggers>
</ToggleButton>

Related

Animate grid background color using storyboard in WPF

I'm new to WPF storyboard. I want to animate grid background color. I'm getting this error:
System.InvalidOperationException: 'Cannot resolve all property
references in the property path 'Background.Color'. Verify that
applicable objects support the properties.'
My XAML code:
<Grid x:Name="alert_grid">
<Grid.Resources>
<Storyboard x:Key="flashing_storyboard" Storyboard.TargetName="alert_grid">
<ColorAnimation
Storyboard.TargetProperty="Background.Color"
From="Black" To="Orange" Duration="0:0:2"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</Grid.Resources>
</Grid>
Code behind:
Storyboard sb = alert_grid.FindResource("flashing_storyboard") as Storyboard;
if (sb != null)
{
sb.Begin();
}
Any idea how to get the background color animated?
Please try this.
<Grid Name="alert_grid" Height="75" HorizontalAlignment="Left" Margin="27,12,0,0" VerticalAlignment="Top" Width="160" Background="LightGray">
<Grid.Triggers>
<EventTrigger RoutedEvent="Button.MouseLeave">
<BeginStoryboard>
<Storyboard x:Name ="flashing_storyboard" Storyboard.Target="{Binding ElementName=alert_grid}">
<ColorAnimation To="Orange" Storyboard.TargetProperty="(Grid.Background).(SolidColorBrush.Color)" From="Black"
AutoReverse="True" RepeatBehavior="Forever" FillBehavior="Stop" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
and code behind
Storyboard sb = alert_grid.FindName("flashing_storyboard") as Storyboard;
if (sb != null)
{
sb.Begin();
}

WPF mouse click returns storyboard to previous state

This piece of code animates the movement of an ellipse if click on this. How can I return (in an animated way - as the storyboard does) the ellipse in the initial position by clicking again on its new position. Is that possible? (preferably only in XAML)
<Ellipse x:Name="circle_button" HorizontalAlignment="Left" Height="100" Margin="30,40,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Ellipse.MouseDown" >
<BeginStoryboard>
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="30,40,0,0" />
<SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="95,120,0,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
An alternative is to use visual states and simply switch between them in code-behind. That might be more clearer approach compared to holding animations as resources.
xaml:
<Ellipse x:Name="circle_button"
HorizontalAlignment="Left"
Height="100"
Margin="30,40,0,0"
VerticalAlignment="Top"
Width="100"
Fill="#FF33D3A7"
MouseDown="circle_button_MouseDown">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="A">
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin">
<SplineThicknessKeyFrame KeyTime="0:0:0.4" Value="95,120,0,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="B">
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin">
<SplineThicknessKeyFrame KeyTime="0:0:0.4" Value="30,40,0,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Ellipse>
cs:
bool _isStateB;
void circle_button_MouseDown(object sender, MouseButtonEventArgs e)
{
_isStateB = !_isStateB;
VisualStateManager.GoToElementState(circle_button, _isStateB ? "B" : "A", true);
}
Demo:
Instead of Ellipse a Button can be used (with style containing such ellipse), then you'll have Click event and ability to focus and click element with keyboard.
P.S.: after writing the answer I suddenly have a though.. ToggleButton has 2 states, you can in fact use IsChecked to toggle between 2 positions (and run different animations)... until you add third, then solution with visual states is preferable.
I think that one of possible ways is to define to storyboard and use some code behind to trigger animations.
Here is an example:
Xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Storyboard x:Key="ElipseStoryboard">
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="30,40,0,0" />
<SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="95,120,0,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="ElipseStoryboardReversed">
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="95,120,0,0" />
<SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="30,40,0,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Grid x:Name="CP">
<Ellipse x:Name="circle_button" MouseDown="Circle_button_OnMouseDown" HorizontalAlignment="Left" Height="100" Margin="30,40,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
</Ellipse>
</Grid>
</Window>
Code behind:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private bool flag = false;
private void Circle_button_OnMouseDown(object sender, MouseButtonEventArgs e)
{
if (flag)
{
var storyboard = this.Resources["ElipseStoryboard"] as Storyboard;
if (storyboard != null)
storyboard.Begin(circle_button);
}
else
{
var storyboard = this.Resources["ElipseStoryboardReversed"] as Storyboard;
if (storyboard != null)
storyboard.Begin(circle_button);
}
flag = !flag;
}
}
}
Please try it.
Alternative only Xaml solution :
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="CP">
<Ellipse x:Name="circle_button" HorizontalAlignment="Left" Height="100" Margin="30,40,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Ellipse.MouseDown" >
<BeginStoryboard>
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="30,40,0,0" />
<SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="95,120,0,0" />
</ThicknessAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button"
From="1.0" To="0.0" Duration="0:0:0" BeginTime="00:00:00.4"></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button2"
From="0.0" To="1.0" Duration="0:0:0" BeginTime="00:00:00.4"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
<Ellipse x:Name="circle_button2" Opacity="0" HorizontalAlignment="Left" Height="100" Margin="95,120,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Ellipse.MouseDown" >
<BeginStoryboard>
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00" Storyboard.TargetName="circle_button">
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="95,120,0,0" />
<SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="30,40,0,0" />
</ThicknessAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button2"
From="1.0" To="0.0" Duration="0:0:0" ></DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button"
From="0.0" To="1.0" Duration="0:0:0"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
</Grid>
</Window>

Why is my UserControl anmation being triggered on all instances of the control?

So in the WPF project I'm just starting I have a UserControl that will be eventully functioning as a sort of document tab (I have simplified the code for this question). On the UserControl is a TextBlock, and the desired behavior is that when the user mouses over the control the text should change color. The XAML below works (resources defined in another file) BUT the ColorAnimation happens to every instance of the UserControl, not just the one I'm mousing over. So if I scatter some of these controls over the UI and mouse over one of them, ALL of them change color. Why??? I've tried adding the triggers to the UserControl, the Grid, and the TextBlock itself but it appears to make no difference. As ever, grateful for any advice.
<UserControl x:Class="OurCompany.TabControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Height="24" Width="Auto">
<UserControl.Resources>
<Storyboard x:Key="MouseEnterFade">
<ColorAnimation Storyboard.TargetName="TabTitleText" Storyboard.TargetProperty="Foreground.Color"
Duration="0:0:0.1"
To="{DynamicResource FrameBorderColor}"/>
</Storyboard>
<Storyboard x:Key="MouseLeaveFade">
<ColorAnimation Storyboard.TargetName="TabTitleText" Storyboard.TargetProperty="Foreground.Color"
Duration="0:0:0.1"
To="{DynamicResource MenuForegroundColor}"/>
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MouseEnterFade}"/>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource MouseLeaveFade}"/>
</EventTrigger.Actions>
</EventTrigger>
</UserControl.Triggers>
<Grid x:Name="TabGrid" Background="Transparent">
<TextBlock x:Name="TabTitleText" Text="{Binding Path=Header}" Margin="10,0,10,0" Foreground="{DynamicResource MenuForegroundBrush}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</UserControl>

WPF C# Roulette Game

I want to create roulette game in WPF C# below mentioned code is working properly but I want to stop wheel after 3 second but I am not getting the way to do it. Kindly help me out with same
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="WpfApplication2.MainWindow" Title="MainWindow" WindowState="Maximized">
<Canvas>
<Canvas.Background>
<ImageBrush ImageSource="Image/Background.jpg" AlignmentX="Right" AlignmentY="Bottom" Stretch="None"/>
</Canvas.Background>
<Ellipse Height="250" Width="250" Margin="200,100,-200,-100">
<Ellipse.Fill>
<ImageBrush x:Name="p2" ImageSource="Image/p2.png"/>
</Ellipse.Fill>
<Ellipse.RenderTransform>
<RotateTransform x:Name="TransRotate11" CenterX="125" CenterY="125"/>
</Ellipse.RenderTransform>
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Image.Loaded">
<BeginStoryboard>
<Storyboard x:Uid="s1" TargetProperty="Angle" RepeatBehavior="Forever">
<DoubleAnimation By="360" Duration="0:0:0.1" Storyboard.TargetName="TransRotate11" Storyboard.TargetProperty="Angle" FillBehavior="Stop"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
</Canvas>
If the duration of the animation is 0.1 seconds and you want it to run for 3 seconds, why not simply set its RepeatBehavior to 30 times:
<Storyboard x:Uid="s1">
<DoubleAnimation Storyboard.TargetName="TransRotate11"
Storyboard.TargetProperty="Angle"
By="360" Duration="0:0:0.1"
RepeatBehavior="30x" FillBehavior="Stop" />
</Storyboard>

Reuse animations in Windows 8

I am building Windows Store Application (Winrt, Metro, Windows 8 app). I try give images in gridview animation: after image is loaded from web and opened it populates its cell.
I have storyboard for that:
<Storyboard x:Name="PopupImageStoryboard">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="image">
<EasingDoubleKeyFrame KeyTime="0" Value="100"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="240"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="image">
<EasingDoubleKeyFrame KeyTime="0" Value="100"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="240"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
And I have such C# code for handling event that image loaded and opened:
private void Image_ImageOpened(object sender, RoutedEventArgs e)
{
Storyboard.SetTarget(PopupImageStoryboard, sender as Image);
PopupImageStoryboard.Begin();
}
It does not work, I can not change target and rerun same storyboard while it is running. But I want multiple images run this animation simultaneously. Can you recommend any solution for animation reuse ?
You should remove this from each of the child animations:
Storyboard.TargetName="image"
Then also I think a single Storyboard might not be possible to be used on two target elements at the same time, so the solution for that would be to put it in a DataTemplate, e.g.
<Page.Resources>
<DataTemplate
x:Name="myStoryboard">
<Storyboard ... />
</DataTemplate>
</Page.Resources>
Then in code you would say
var sb = (Storyboard)myStoryboard.LoadContent();
Storyboard.SetTarget(sb, sender as Image);
sb.Begin();
BTW - do not animate Width and Height properties. This is almost certainly not the best idea in your case. You should animate your RenderTransform properties instead, e.g. targeting ScaleTransform's ScaleX and ScaleY properties. If an animation is a dependent - it will cause layout updates in each frame which is very inefficient and will degrade your animation frame rate.
*EDIT
A better solution then would look like this:
<Page.Resources>
<DataTemplate
x:Name="myStoryboardTemplate">
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="ScaleX"
From="0.5"
To="1.0"
Duration="0:0:0.4">
<DoubleAnimation.EasingFunction>
<BackEase
Amplitude="2"
EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetProperty="ScaleY"
From="0.5"
To="1.0"
Duration="0:0:0.4">
<DoubleAnimation.EasingFunction>
<BackEase
Amplitude="2"
EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</DataTemplate>
</Page.Resources>
...
<Image
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="620"
Height="300"
Source="Assets/SplashScreen.png"
RenderTransformOrigin="0.5,0.5"
Stretch="Fill">
<Image.RenderTransform>
<ScaleTransform
x:Name="imageScaleTransform" />
</Image.RenderTransform>
</Image>
...
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var sb = (Storyboard)myStoryboardTemplate.LoadContent();
Storyboard.SetTarget(sb, imageScaleTransform);
sb.Begin();
}

Categories

Resources