I have a page,page have canvas,in canvas exist image,and exist animation.
Animation(beginning on datatrigger) must move image from Canvas.Left to ActualWidth of Canvas.
It's easy at first sight :) but...
Binding don't wokring,im trying to solve this for 2 days (((
I have two solutions for this problem, but none is complete.
Solution 1: DataTrigger - Working. Binding "To" - Don't woking.
<ContentControl>
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<ControlTemplate.Resources>
<Storyboard x:Key="EnemyAnimation" Storyboard.TargetName="Xenomorph" Storyboard.TargetProperty="(Canvas.Left)">
<DoubleAnimation From="0" To="{Binding ElementName=Canvas1,Path=ActualWidth}" BeginTime="0:0:3" Duration="0:0:10" />
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding startAi}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource EnemyAnimation}" />
</DataTrigger.EnterActions>
</DataTrigger>
</ControlTemplate.Triggers>
<Canvas x:Name="Canvas1" Margin="20" Grid.Row="1">
<Image x:Name="Xenomorph1" Height="100" Width="100" VerticalAlignment="Center" Source="/Mathilvania;component/Resources/Xenomorph.gif" HorizontalAlignment="Center" Margin="10,65,0,0" Grid.Row="1"/>
</Canvas>
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
Solution 2: DataTrigger - I can't add DataTrigger. Binding "To" - Working
<Canvas Name="canv" Margin="50,0,100,0" Grid.Row="1" VerticalAlignment="Center" Height="100">
<Image x:Name="Xenomorph" Height="100" Width="100" VerticalAlignment="Center" Source="/Mathilvania;component/Resources/Xenomorph.gif" HorizontalAlignment="Center" Margin="0" Grid.Row="1"/>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.SizeChanged">
<BeginStoryboard>
<Storyboard TargetName="Xenomorph">
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)"
BeginTime="0:0:1"
Duration="0:0:5"
From="0"
To="{Binding ElementName=canv, Path=ActualWidth}" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
</Canvas>
In Solution 1,i can't Binding "To" but trigger working.In solution 2 Binding work,but DataTrigger,i can't add
UPDATE:
When i add DataTrigger to Solution2 like this:
<Canvas Name="canv" Margin="50,0,100,0" Grid.Row="1" VerticalAlignment="Center" Height="100">
<Image x:Name="Xenomorph" Height="100" Width="100" VerticalAlignment="Center" Source="/Mathilvania;component/Resources/Xenomorph.gif" HorizontalAlignment="Center" Margin="0" Grid.Row="1"/>
<Canvas.Triggers>
<DataTrigger Binding="{Binding startAi}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetName="Xenomorph">
<DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)"
BeginTime="0:0:1"
Duration="0:0:5"
From="0"
To="{Binding ElementName=canv, Path=ActualWidth}" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Canvas.Triggers>
I have an erron:
Elements of the Triggers family must have the type EventTrigger
This is a pretty common problem. You can use the data bindings for the From and To properties of an animation only if it is not in an ControlTemplate or a Style. In these cases, the Animation needs to be sealed (frozen), that's obviously not possible if some its properties change their values dynamically.
There is a workaround solution for this. It isn't neat, but it works. You just have to introduce an intermediate scale factor that you'll be animating with a hard-coded Animation. But the actual value will be then calculated using a multiplying IMultiValueConverter on a MultiBinding.
Here is an example.
The converter could look like this:
public class MultiplyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.OfType<double>().Aggregate(1.0, (current, t) => current * t);
}
// ConvertBack omitted...
}
And in XAML, you can use the Tag of your object for holding the animated scale factor.
Something like this:
<Canvas x:Name="Canvas" xmlns:l="Your_converter_namespace" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Canvas.Resources>
<l:MultiplyConverter x:Key="MultiplyConverter"/>
</Canvas.Resources>
<Rectangle Height="100" Width="100" Fill="Blue">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Binding="{Binding IsAnimationStarted}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="Storyboard1">
<Storyboard TargetProperty="Tag">
<DoubleAnimation From="0" To="1" Duration="0:0:5"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Storyboard1"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
<Rectangle.Tag>
<sys:Double>0</sys:Double>
</Rectangle.Tag>
<Canvas.Left>
<MultiBinding Converter="{StaticResource MultiplyConverter}">
<Binding Path="ActualWidth" ElementName="Canvas"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Canvas.Left>
</Rectangle>
</Canvas>
You'll see that resizing the Canvas won't cause the animation to start over again, but rather it will seamlessly continue.
Related
So I just got into animations and I wanted to do a "Slide out" animation and I managed to do so just fine.
But now I want it to slide in with the click on the same button.
So like I click it and it slides out and then I want it to slide back in when I click it again.
WITHOUT any code behind, so just through xaml
Here is the XAML
<Grid>
<Grid.Resources>
<Storyboard x:Key="TransformImage">
<DoubleAnimation
Storyboard.TargetName="MovingImage"
Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)"
By="130" Duration="0:0:0.3">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="TransformButton">
<DoubleAnimation
Storyboard.TargetName="btnChange"
Storyboard.TargetProperty="(Button.RenderTransform).(TranslateTransform.X)"
By="130" Duration="0:0:0.3">
</DoubleAnimation>
</Storyboard>
</Grid.Resources>
<Grid.Triggers>
<EventTrigger RoutedEvent="Button.Click" SourceName="btnChange">
<BeginStoryboard Storyboard="{StaticResource TransformImage}"/>
<BeginStoryboard Storyboard="{StaticResource TransformButton}"/>
</EventTrigger>
</Grid.Triggers>
<StackPanel Orientation="Horizontal" Margin="0">
<Image x:Name="MovingImage" Source="logo.png"
MaxWidth="120">
<Image.RenderTransform>
<TranslateTransform />
</Image.RenderTransform>
</Image>
</StackPanel>
<StackPanel
Panel.ZIndex="1"
Height="450"
Width="120"
HorizontalAlignment="Left"
Background="Black"></StackPanel>
<Button Margin="130,0,0,0" Height="40" Width="120"
Content="Show Image" x:Name="btnChange"
HorizontalAlignment="Left" >
<Button.RenderTransform>
<TranslateTransform />
</Button.RenderTransform>
</Button>
</Grid>
You need to store current state of slide animation when clicking on button and based on it run appropriate story board.
For example, you could use ToggleButton that has IsChecked property (or property in view-model).
To avoid duplicate triggers/styles I placed Image and ToggleButton in the same StackPanel.
<Grid>
<Grid.Resources>
<system:Double x:Key="SlideOffSet">130</system:Double>
<Storyboard x:Key="SlideRight">
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
From="0" To="{StaticResource SlideOffSet}"
Duration="0:0:0.3" />
</Storyboard>
<Storyboard x:Key="SlideLeft">
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
From="{StaticResource SlideOffSet}" To="0"
Duration="0:0:0.3" />
</Storyboard>
</Grid.Resources>
<StackPanel Orientation="Horizontal" Margin="0">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=SlideState}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource SlideRight}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource SlideLeft}" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<StackPanel.RenderTransform>
<TranslateTransform />
</StackPanel.RenderTransform>
<Image Source="logo.png" MaxWidth="120" />
<ToggleButton x:Name="SlideState" Margin="10,0,0,0" Height="40" Width="120" Content="Show Image" />
</StackPanel>
<StackPanel
Panel.ZIndex="1"
Height="450"
Width="120"
HorizontalAlignment="Left"
Background="Black"></StackPanel>
</Grid>
Also, I would not recommend using By property of the DoubleAnimation:
If animation is still running and you click button again, then second animation will be started at wrong position (it will use X value from first animation, which is not finished) - Click button quickly many times and you will see the problem.
Use From and To properties instead.
How to make the animation start of the TextBlock when entering (hovering) the button
In TextBlock I want that the <EventTrigger RoutedEvent will be in Input2 at MouseEnter, How can I do that
<EventTrigger RoutedEvent=Input2.MouseEnter doesn't recognized
The button:
<Button Grid.Row="0" Name="Input2" Click="Input_Click" MouseEnter="Input_MouseEnter" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" >
<Image Source= "C:\Users\Me\input.png"
Width="40"
Height="40"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
The TextBlock:
<TextBlock Grid.Row="0" Name="Input_Name1" Text="Input" FontSize="40" FontFamily="/10KHours;component/Font_count/#Dancing Script" VerticalAlignment="Center" Height="48" Margin="65.346,33.6,-102.081,36">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Input_Name1"
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.0" Duration="0:0:5"
AutoReverse="true" RepeatBehavior="1x">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
The basic idea to change the style of the TextBlock is totally correct. Add a DataTrigger and bind it to the the IsMouseOver of the Button you are going to hover. Using the IsMouseOver is propaply the simplest way to get the desired information. Here is a minimal example:
<Button x:Name="btn" Content="Hover me"/>
<TextBlock x:Name="tb" Text="Input">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=btn, Path=IsMouseOver}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.0" Duration="0:0:1"
AutoReverse="true" RepeatBehavior="1x">
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Below my rectangle in WPF:
<Rectangle Margin="5,0" HorizontalAlignment="Left" Width="380" Height="25" Fill="LightYellow" Stroke="Orange" StrokeThickness="2" RadiusX="8" RadiusY="8"/>
I would like to start bliking for some seconds (and then stop) the rectangle stroke property when a property "StartBlinking" in view model changes from false to true.
I would like to implement storyboard in xaml not in c# code.
How can I do this?
I have tried this but not working:
<Rectangle Margin="5,0" HorizontalAlignment="Left" Width="380" Height="25" Fill="LightYellow" Stroke="Orange" StrokeThickness="2" RadiusX="8" RadiusY="8">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Style.Resources>
<Storyboard x:Key="flashAnimation" >
<DoubleAnimation Storyboard.TargetProperty="Stroke" From="1" To="0" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="Forever" />
</Storyboard>
</Style.Resources>
</Style>
</Rectangle.Style>
</Rectangle>
I am using C# and .NET 3.5 in Visual Studio 2008.
You could animate the Opacity property of the Stroke using a DataTrigger and a Storyboard:
<Rectangle Margin="5,0" HorizontalAlignment="Left" Width="380" Height="25" Fill="LightYellow"
Stroke="Orange" StrokeThickness="2" RadiusX="8" RadiusY="8">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Binding="{Binding StartBlinking}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Stroke.(SolidColorBrush.Opacity)"
To="0" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="6x" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Stroke.(SolidColorBrush.Opacity)"
To="1" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
I've got a "flip card"-style animation that works just fine. On one side, it has a button that, when clicked, triggers the animation "FlipOpen":
<Button Content="click me" Height="130">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click" >
<BeginStoryboard Storyboard="{StaticResource FlipOpen}">
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
<Storyboard x:Key="FlipOpen">
<DoubleAnimation Duration="00:00:0.5" Storyboard.TargetProperty="RenderTransform.ScaleX" From="-1" To="1" Storyboard.TargetName="Back"/>
<DoubleAnimation Duration="00:00:0.5" Storyboard.TargetProperty="RenderTransform.ScaleX" From="1" To="-1" Storyboard.TargetName="Front"/>
</Storyboard>
<Storyboard x:Key="FlipClose">
<DoubleAnimation Duration="00:00:0.5" Storyboard.TargetProperty="RenderTransform.ScaleX" From="1" To="-1" Storyboard.TargetName="Back"/>
<DoubleAnimation Duration="00:00:0.5" Storyboard.TargetProperty="RenderTransform.ScaleX" From="-1" To="1" Storyboard.TargetName="Front"/>
</Storyboard>
I would like to bind the animation to a boolean property on my ViewModel and I have tried to use DataTriggers:
a) define a style:
<Style x:Key="myStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding FlipTheCard}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FlipOpen}"/>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding FlipTheCard}" Value="false">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FlipClose}"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
b) apply it to both Grid-Containers that contain the front and back:
<Grid RenderTransformOrigin="0.5,0.5" x:Name="Back" Opacity="0" Style="{StaticResource myStyle}">
...
</Grid>
c) don't start the animation on button click, but bind a command that toggles the boolean to the button:
<Button Content="click me!" Command="{Binding ToggleFlipCard}" Height="130">
However, this results in an exception ("A storyboard-structure within a Style can not have a TargetName. Remove the TargetName").
What am I doing wrong here? How can I bind these animations to a boolean property on my ViewModel?
Thank you for any help!
I've also found a solution...it's far from perfect on the animation side (as I don't use keyframes and just scale the x property of both at the same time) but it should give you the idea:
Style:
<Storyboard x:Key="FlipOpen">
<DoubleAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleX)"
To="0" />
</Storyboard>
<Storyboard x:Key="FlipClose">
<DoubleAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleX)"
From="0"
To="1" />
</Storyboard>
<Style x:Key="GridStyle" TargetType="Grid">
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="1" ScaleY="1" />
</Setter.Value>
</Setter>
</Style>
<Style x:Key="FrontGridStyle" TargetType="Grid"
BasedOn="{StaticResource GridStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding FlipTheCard}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FlipOpen}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource FlipClose}" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="BackGridStyle" TargetType="Grid"
BasedOn="{StaticResource GridStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding FlipTheCard}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FlipClose}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource FlipOpen}" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
Grid:
<Grid>
<Grid Style="{StaticResource FrontGridStyle}">
<Border Width="100"
Height="100"
Background="Red" />
<Button HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding ToggleFlipCard}"
Content="click me!" />
</Grid>
<Grid Style="{StaticResource BackGridStyle}">
<Border Width="100"
Height="100"
Background="Green" />
<Button HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding ToggleFlipCard}"
Content="click me!" />
</Grid>
</Grid>
I found a solution.. yikes
reference Microsoft.Expression.Interactions.dll
define Interaction-Triggers:
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding FlipToFront}" Value="true">
<ei:ControlStoryboardAction Storyboard="{StaticResource FlipOpen}"/>
</ei:DataTrigger>
<ei:DataTrigger Binding="{Binding FlipToFront}" Value="false">
<ei:ControlStoryboardAction Storyboard="{StaticResource FlipClose}"/>
</ei:DataTrigger>
</i:Interaction.Triggers>
credits
How do I conditionally get this animation to run, depending on a bool CanAnimate? It works right now, but I don't always want it to be animated, I want to check the boolean.
<Border BorderBrush="Black" BorderThickness="2" Margin="1" Name="ReviewNote">
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ReviewNote"
Storyboard.TargetProperty="(Border.Opacity)"
From="1.0" To="0.0" AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<TextBlock Text="{x:Static Constants:StringConstants.ReviewNote}"
Background="{StaticResource ReviewNoteColor}" Width="100"
TextAlignment="Center" />
</Border>
Apply style on your border and inside style you can check value of bool property. Based on that property you can specify DataTrigger.EnterActions with storyboard after removing TargetName from storyBoard.
This will work -
<Border BorderBrush="Black" BorderThickness="2" Margin="1" Name="ReviewNote">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding CanAnimate}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Border.Opacity)"
From="1.0" To="0.0" AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock/>
</Border>