How to animate multiple Path elements in WPF - c#

I have a collection of glyphs that are in form of WPF <Path> elements.
Something like this:
<Grid>
<Path Data="..." Height="33.333" Stretch="Fill" Width="33.334"/>
<Path Data="..." Height="33.333" Stretch="Fill" Width="33.334"/>
<Path Data="..." Height="33.333" Stretch="Fill" Width="33.334"/>
<Path Data="..." Height="33.333" Stretch="Fill" Width="33.334"/>
</Grid>
These are just image or icon glyphs. I'm trying to find a way to switch or flip between these various Path elements so that it looks like an animation. I'm pretty new to WPF and have tried looking for examples but couldn't find anything similar here or elsewhere on the web. The closest example I found was erasing one <Image> element with another using Storyboard and DoubleAnimation but I can't figure out how to apply it to <Path>.
I'm basically trying to find a way to show one path element and hide all other paths, wait a second, show next path element and hide all other, and so on, to make it look like a flip animation.
I would appreciate if someone can post a simple example or point me in the right direction. Thanks.

Alright give this a try. Note that each Path will get its own Storyboard. So if you have 4 Paths, you get 4 Storyboards.
<Path>
<Path.Style>
<Style TargetType="{x:Type Path}">
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="00:00:1"
BeginTime="00:00:1"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
<Path>
<Path.Style>
<Style TargetType="{x:Type Path}">
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0" To="1"
Duration="00:00:1"
BeginTime="00:00:2"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
<Path>
<Path.Style>
<Style TargetType="{x:Type Path}">
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0" To="1"
Duration="00:00:1"
BeginTime="00:00:3"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
<Path>
<Path.Style>
<Style TargetType="{x:Type Path}">
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0"
To="1"
Duration="00:00:1"
BeginTime="00:00:4"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
Notice how we're using the FrameworkElement.Loaded event to trigger the animation. You can use this event on virtually any UI element. Each storyboard changes the opacity from 0 (invisible) to 1 (completely visible) in 1 second (you can change this using the Duration property). Also, the BeginTime property is different for each storyboard, this is required to make sure the items are animated one after another. Finally, we set the AutoReverse property to make sure the Paths are disappeared (i.e. the animation is reversed). This should give you the idea.

Related

How do I fill the button background with a circle on click

I want to be able to click my button and on the click trigger I want the background to fill up with a circle, much like how a materialistic button would. I know there is a library for this but I'd much rather develop my own because I want to learn.
This is what it would look like when you click, rather than when you move the mouse out of it.
I've tried playing around with the style of the button, trying to make some animation using storyboards but I can't seem to figure it out.
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard BeginTime="00:00:00"
RepeatBehavior="Forever"
AutoReverse="True"
Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)">
<ColorAnimation From="Black" To="Red" Duration="0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
When I click the button I want the background to fill up starting from a circle shape (the button shouldn't be circle shaped), filling up the rest of the button, what I am seeing now is just a fading color of the entire thing which is not what I was expecting.
Here is an example of such an effect.
I just used a Rectangle, not a Button, for simplicity. But you surely can apply this technique to any control.
The events MouseEnter and MouseLeave are used here, but you can replace them with click events or whatever you need.
<Rectangle Width="150" Height="150" Stroke="Black" StrokeThickness="1">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard Duration="0:0:1">
<!-- we just scale the brush in this animation -->
<DoubleAnimation From="0" To="2" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Transform).(ScaleTransform.ScaleX)"/>
<DoubleAnimation From="0" To="2" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Transform).(ScaleTransform.ScaleY)"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard Duration="0:0:1">
<DoubleAnimation From="2" To="0" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Transform).(ScaleTransform.ScaleX)"/>
<DoubleAnimation From="2" To="0" Storyboard.TargetProperty="(Rectangle.Fill).(DrawingBrush.Transform).(ScaleTransform.ScaleY)"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
<Rectangle.Fill>
<!-- the rectangle's fill is a brush which can be scaled -->
<DrawingBrush>
<DrawingBrush.Transform>
<!-- the initial scale values are 0, so we don't see the fill -->
<ScaleTransform ScaleX="0" ScaleY="0" CenterX="75" CenterY="75"/>
</DrawingBrush.Transform>
<DrawingBrush.Drawing>
<GeometryDrawing Brush="MediumBlue">
<GeometryDrawing.Geometry>
<EllipseGeometry RadiusX="150" RadiusY="150" Center="75,75" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>

Animatint BlurEffect in a style works but animating DropShadowEffect causes error?

I am trying to animate a DropShadowEffect I have applied to one grid and a BlurEffect that I have applied to another grid.
The blur animation seems to work fine and this is the code.
<Style x:Key="BluredGridStyle" TargetType="{x:Type Grid}">
<Style.Triggers>
<Trigger Property="extentions:GridExtention.IsBlured" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Effect).Radius" From="0" To="10" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Effect).Radius" From="10" To="0" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
<Grid Background="{DynamicResource BrHostBackground}">
<Grid extentions:GridExtention.IsBlured="{Binding BackgroundIsBlured}" Style="{StaticResource BluredGridStyle}">
<Grid.Effect>
<BlurEffect x:Name="BlurEffect" Radius="0"/>
</Grid.Effect>
</Grid>
</Grid>
But when I try with the drop shadow I get errors. Here is my initial code.
<Style x:Key="DropShaodowGridStyle" TargetType="{x:Type Grid}">
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Effect).BlurRadius" From="0" To="80" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Effect).BlurRadius" From="80" To="0" Duration="0:0:0.2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
<Grid Visibility="{Binding HardwareLoadingVisibility}">
<Grid x:Name="grid" HorizontalAlignment="Center" VerticalAlignment="Center" Background="White" Width="550" Height="250" Style="{DynamicResource DropShaodowGridStyle}">
<Grid.Effect>
<DropShadowEffect ShadowDepth="0" Opacity="0.8"/>
</Grid.Effect>
</Grid>
</Grid>
This generates the following error
InvalidOperationException: Cannot resolve all property references in the property path '(Effect).BlurRadius'. Verify that applicable objects support the properties.
If I change the property to (Effect).Radius I get the same error.
I also tried changing the property to (UIElement.Effect).(DropShadowEffect.BlurRadius) which generated this error
InvalidOperationException: 'Effect' property does not point to a DependencyObject in path '(0).(1)'.
Looks like I found the answer.
I had to assign a default value to the property in the style.
<Style x:Key="DropShaodowBorderStyle" TargetType="{x:Type Border}">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="0" BlurRadius="0"></DropShadowEffect>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Effect).BlurRadius" From="0" To="80" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.Effect).BlurRadius" From="80" To="0" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>

Activate Storyboard on Visibility Changed

Currently I have an Image that I pulse when it is loaded. I want to rather activate the Storyboard when I change the Visibility of the Image. But I see that Image.Triggers have to be EventTriggers.
Which event do I need to hook into?
<Image.Triggers>
<EventTrigger RoutedEvent="Image.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MandateErrorImage"
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.1" Duration="0:0:0.5"
AutoReverse="True" RepeatBehavior="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
In WPF there is an event UIElement.IsVisibleChanged but is a CLR event, not a routed event, therefore in EventTrigger can not be used.
In this case use IsVisible property in DataTrigger like this:
<Window.Resources>
<Style x:Key="AnimationImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=IsVisible}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="1.0" To="0.1"
Duration="0:0:0.5"
AutoReverse="True"
RepeatBehavior="0:0:2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Image Name="TestImage"
Style="{StaticResource AnimationImageStyle}"
Source="Enter.jpg"
Width="400"
Height="400" />
</Grid>
If you want to animate on a DependencyProperty or bound value you will need to create a Style for your image and put the animation in the style.
The following Style will perform your animation when the Visibility of your image is set to Visible:
<Style x:Key="FlashingImageStyle" TargetType="{x:Type Image}">
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.1" Duration="0:0:0.5"
AutoReverse="True" RepeatBehavior="0:0:2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>

Polygon Animation won't work in c#

I am having a small Problem in C#. I want to have a Polygon I drew in WPF to be animated on hover.
I successfully drew the polygon like this:
<Polygon Fill="#FF767676" Points="0,8,12,0,12,16" Margin="30" Style="{DynamicResource BackAndForth}"/>
I then defined a style
<Style x:Key="BackAndForth" TargetType="{x:Type Polygon}">
<Setter Property="Opacity" Value="0.6" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Opacity" From="0.6" To="1" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Opacity" From="1" To="0.6" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
Somehow this won't work. The setter property in line 2 works. But somehow the animation won't get triggered. I already looked it up but polygons have a IsMouseOver Property.
The exact same code works perfecty on buttons (with a proper target type).
Any ideas what I am missing?

Load all the effect of storyboard until it's finish

I have an image which when pressed by user, the opacity will fade until value 0. But the effect only continues if user press and hold the image. Is there a possible way to change the code to: When user press, and without holding the press, the opacity fading effect will stay? I wish to do it in XAML.
<EventTrigger RoutedEvent="Button.Click" SourceName="press">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource showA}"/>
</EventTrigger.Actions>
</EventTrigger>
<Button Grid.Column="5" Command="{Binding Path=PressC}" CommandParameter="dot" Style="{StaticResource TransparentButton}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Image Name="image5" Source="/W;component/Images/t.png" Height="100" />
<Image Name="pressed5" Source="/W;component/Images/T.png" Height="100" Width="200" Margin="-23,-136,-21,0" Visibility="Hidden" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="pressed5" Storyboard.TargetProperty="Opacity" Duration="0:0:1.5" From="1" To="0"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Setter Property="Panel.ZIndex" Value="999"/>
<Setter TargetName="pressed5" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
Can you show your full xaml? Because Image does not have IsPressed property and it is not clear how it works for you.
Similar code for button works as expected:
<Button Background="Aquamarine">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:1.5" From="1" To="0"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
And for Image it works too with EventTrigger:
<Image Source="d:\123.png">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<EventTrigger RoutedEvent="MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="0:0:1.5" From="1" To="0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Image.Style>

Categories