WPF ListView animation - c#

I am trying to make ListViewItem which would increase after button click. But I have some problem when animation start's increasing it's overlap nearest items.
How can it be solved?
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.27"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="1.562"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="6.75"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="5.625"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</DataTemplate.Resources>
<Grid x:Name="grid" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding .}"></Label>
<Button Grid.Column="1" Content="{Binding .}" Width="40">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"></BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Problem is in ListViewItem size, because it doesn't change?

Related

Making Storyboards into resources that can be used by multiple controls in WPF

I have a working animation, now I am placing it in Apps.xaml under application.Resources, with all necessary bindings but it doesn't work. Am I missing something in the binding process? What is the proper way to bind the Storyboard.Targetname?
<Storyboard x:Key="RotateIn">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="button2">
<EasingDoubleKeyFrame KeyTime="0" Value="-100"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="button2">
<EasingDoubleKeyFrame KeyTime="0" Value="50"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="button2">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="10"
To="360"
Duration="0:0:0.7"
FillBehavior="Stop" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="textBlock">
<EasingDoubleKeyFrame KeyTime="0" Value="90"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Button Grid.Column="1" Name="btn2" Width="150" Height="150" Background="gray">
<StackPanel >
<Image Source="{StaticResource img2}" x:Name="button2" RenderTransformOrigin=".5,.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="0" x:Name="AnimatedRotateTransform"/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<TextBlock x:Name="textBlock" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>Rotate In</TextBlock>
</StackPanel>
</Button>
Above is my working animation created for a single Control. However, when I tried to make it into a resource where it can be reused like
here , (H.B.)'s answer :
<Application.Resources>
<ResourceDictionary>
<Storyboard x:Key="BindingRotate" x:Shared="False">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="{DynamicResource AnimationTarget}">
<EasingDoubleKeyFrame KeyTime="0" Value="-100"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="{DynamicResource AnimationTarget}">
<EasingDoubleKeyFrame KeyTime="0" Value="50"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity" Storyboard.TargetName="{DynamicResource AnimationTarget}">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="{DynamicResource AnimationTarget1}"
Storyboard.TargetProperty="Angle"
By="10"
To="360"
Duration="0:0:0.7"
FillBehavior="Stop" />
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="{DynamicResource AnimationTarget2}">
<EasingDoubleKeyFrame KeyTime="0" Value="90"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ResourceDictionary>
</Application.Resources>
<Button Grid.Column="1" Name="btn2" Width="150" Height="150" Background="gray">
<StackPanel >
<Image Source="{StaticResource img2}" x:Name="button2" RenderTransformOrigin=".5,.5">
<Image.Resources>
<sys:String x:Key="AnimationTarget">button</sys:String>
</Image.Resources>
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="0" x:Name="AnimationTarget1">
</RotateTransform>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<TextBlock x:Name="textBlock" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5" Text="Rotate In">
<TextBlock HorizontalAlignment="Center" Text="Expand In">
<TextBlock.Resources>
<sys:String x:Key="AnimationTarget2">button</sys:String>
</TextBlock.Resources>
</TextBlock>
</TextBlock>
</StackPanel>
<Button.Triggers>
<EventTrigger RoutedEvent="ButtonBase.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource BindingRotate}"/>
</EventTrigger>
</Button.Triggers>
</Button>
''[Unknown]' property does not point to a DependencyObject in path '(0).(1)[3].(2)'.'
Exception is all I get. I followed exactly what was stated in the answer. Please let me know what is missing in my binding as I could not find related topic.
Another question, is there any way for me to set
<sys:String x:Key="AnimationTarget1">button</sys:String>
into
<RotateTransform.Resources>
as I did to other controls? Thank you for your time. I am still quite new to WPF.
Define the resources that you are referring to in your Storyboard, i.e. AnimationTarget, AnimationTarget1 and AnimationTarget2, in the Resources property of the Button where the EventTrigger is defined. This works for me:
<Button Grid.Column="1" Name="btn2" Width="150" Height="150" Background="gray">
<Button.Resources>
<sys:String x:Key="AnimationTarget">button2</sys:String>
<sys:String x:Key="AnimationTarget1">AnimatedRotateTransform</sys:String>
<sys:String x:Key="AnimationTarget2">button2</sys:String>
</Button.Resources>
<StackPanel >
<Image Source="{StaticResource img2}" x:Name="button2" RenderTransformOrigin=".5,.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform x:Name="AnimatedRotateTransform" Angle="0" />
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<TextBlock x:Name="textBlock" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5" Text="Rotate In">
<TextBlock HorizontalAlignment="Center" Text="Expand In" />
</TextBlock>
</StackPanel>
<Button.Triggers>
<EventTrigger RoutedEvent="ButtonBase.MouseEnter">
<BeginStoryboard Storyboard="{StaticResource BindingRotate}"/>
</EventTrigger>
</Button.Triggers>
</Button>

how to apply storyboard animation to multiple xaml element

I have created a storyboard animation, and it works for my one XAML element, however how can i apply it to multiple XAML elements ones?
here is the XAML:
<Storyboard x:Name="FlipOpen">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="Front">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="-90"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="Back">
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="-270"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="-360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
and the controlled XAML:
<StackPanel Background="Blue" Width="420" x:Name="Front">
<StackPanel.Projection>
<PlaneProjection/>
</StackPanel.Projection>
<TextBlock Text="Front" FontSize="25" Height="40"/>
<TextBlock Text="alcim" FontSize="10" Height=" 20"/>
</StackPanel>
<StackPanel x:Name="Back" Width="420" Background="Red">
<StackPanel.Projection>
<PlaneProjection RotationY="-270" />
</StackPanel.Projection>
<TextBlock Text="Hátlap"/>
</StackPanel>
</Grid>
How can i create the controlled party in code (multiple times), and then apply the storyboard to it? because they can't have the same x:Name property...
Define your storyboard as a resource and reference it from the controls you want animate or from a style.
<Storyboard x:Key="FlipOpenStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="-90"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
Define in the stack panel when you want start the animation.
<StackPanel Background="Blue" Width="420" x:Name="Front">
<StackPanel.Triggers>
<EventTrigger RoutedEvent="StackPanel.Loaded">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource FlipOpenStoryboard}" />
</EventTrigger.Actions>
</EventTrigger>
</StackPanel.Triggers>
<StackPanel.Projection>
<PlaneProjection/>
</StackPanel.Projection>
<TextBlock Text="Front" FontSize="25" Height="40"/>
<TextBlock Text="alcim" FontSize="10" Height=" 20"/>
</StackPanel>
I don't have the PlaneProjection control so below I provide you a working example of animating the Height of the panel.
The animation:
<Storyboard x:Key="FlipOpenStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Height" >
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:4" Value="500"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
The panel:
<StackPanel Background="Blue" Width="420" Height="100">
<StackPanel.Triggers>
<EventTrigger RoutedEvent="StackPanel.Loaded">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource FlipOpenStoryboard}" />
</EventTrigger.Actions>
</EventTrigger>
</StackPanel.Triggers>
<TextBlock Text="Front" FontSize="25" Height="40"/>
<TextBlock Text="alcim" FontSize="10" Height=" 20"/>
</StackPanel>

WPF animate button Image

I have a button on which I am adding 2 images. Later on I have to put animation on these images of button.
In below Xaml code I am using button template but after applying the templates button original behavior is lost like there is no border, no change on mouse cursor when hover etc. It is just apear as plan image.
How can I put back the button default behaviour?
<Button Height="89" Margin="0,62,158,0" Name="buttonStart" VerticalAlignment="Top" Click="buttonStart_Click" HorizontalAlignment="Right" Width="133" >
<Button.Template>
<ControlTemplate TargetType="Button" >
<Grid>
<Image x:Name="Normal" Source="/TFSCheckinReportGenerator;component/Resource/generate.png" Height="80" Width="80" Opacity="1"></Image>
<Image x:Name="Waiting" Source="/TFSCheckinReportGenerator;component/Resource/waiting.png" Height="80" Width="80" Opacity="0"></Image>
</Grid>
<ControlTemplate.Resources>
<Storyboard x:Key="ChangeImageToWaiting">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Normal" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Waiting" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Progress" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Waiting" Storyboard.TargetProperty="Width" Duration="00:00:01" AutoReverse="True">
<SplineDoubleKeyFrame Value="40"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Waiting" Storyboard.TargetProperty="Height" Duration="00:00:01" AutoReverse="True">
<SplineDoubleKeyFrame Value="40"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
</ControlTemplate>
</Button.Template>
</Button>
Instead of Template and ControlTemplate use ContentTemplate and DataTemplate and it will helps to show button original behavior like border and change button appearance on mouse hover etc.
Template defines the appearance of the control. ContentTemplate specifies how the content contained in/displayed by a ContentControl is to be displayed.
<Button Height="89" Margin="0,62,158,0" Name="buttonStart" VerticalAlignment="Top" HorizontalAlignment="Right" Width="133" >
<Button.ContentTemplate>
<DataTemplate>
<Grid>
<Image x:Name="Normal" Source="catalogscreen.png" Height="80" Width="80" Opacity="1"></Image>
<Image x:Name="Waiting" Source="catalogscreen.png" Height="80" Width="80" Opacity="0"></Image>
</Grid>
<DataTemplate.Resources>
<Storyboard x:Key="ChangeImageToWaiting">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Normal" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Waiting" Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Progress" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Waiting" Storyboard.TargetProperty="Width" Duration="00:00:01" AutoReverse="True">
<SplineDoubleKeyFrame Value="40"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Waiting" Storyboard.TargetProperty="Height" Duration="00:00:01" AutoReverse="True">
<SplineDoubleKeyFrame Value="40"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</DataTemplate.Resources>
</DataTemplate>
</Button.ContentTemplate>
</Button>

my storyboard skips some keyframes

I would like to swing an ellipse to one place and then shrink it. After the first storyboard stops, I intend to stretch the ellipse with the ellipse. However the shrinking process doesn't work at all. Hard to firgure out why~ Any help or tips will be appreciated. Thanks~
<Window.Resources>
<Storyboard x:Key="Swing" Duration="0:0:7">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="Leg" AutoReverse="True" RepeatBehavior="Forever">
<EasingDoubleKeyFrame KeyTime="0" Value="27.081"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-25.783"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="Leg">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:6" Value="489.676"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Leg">
<EasingDoubleKeyFrame KeyTime="0:0:6" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:7" Value="0.2"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="Swing2" BeginTime="0:0:7">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Leg">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0.2"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard x:Name="Swing_BeginStoryboard" Storyboard="{StaticResource Swing}"/>
<BeginStoryboard x:Name="Swing_BeginStoryboard1" Storyboard="{StaticResource Swing2}"/>
</EventTrigger>
</Window.Triggers>
<Grid x:Name="LayoutRoot">
<Ellipse x:Name="Leg" Fill="#FFF4F4F5" HorizontalAlignment="Left" Margin="156,204,0,147" Stroke="Black" Width="33" RenderTransformOrigin="0.464,-0.014">
<Ellipse.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="27.081"/>
<TranslateTransform/>
</TransformGroup>
</Ellipse.RenderTransform>
</Ellipse>
</Grid>
If I change the second storyboard as below, the ellipse will be shinking from the beginning.
<Storyboard x:Key="Swing2">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Leg">
<EasingDoubleKeyFrame KeyTime="0:0:7" Value="0.2"/>
<EasingDoubleKeyFrame KeyTime="0:0:9" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

Animated split-flap display

I'd like to create an animated split-flap display using c# / wpf. I want it to look similar to the one, that can be seen in this video, but without the 3D effect. As I don't have a lot experience with wpf, I'd like to know how I can implement a UserControl for a single animated letter.
Without 3d, you could do this with multiple images.
Idea #1 Think animated gif. Only, you would have a one set of images to flip from 1 to 2. Another set of images to flip from 2 to 3, etc...
See Option 2 at this site:
http://www.wpfsharp.com/2011/05/11/wpf-replacement-options-for-an-animated-gif
Then you would have the click start the storyboard, then end at a new image instead of the same image. The more images you have, the less choppy it will be.
Idea #2
My other idea would use a top and bottom image for each number. Bend the images with RenderTransform changes.
Give this a look. I got it halfway there for you:
<Window.Resources>
<Storyboard x:Key="FlipNumberStoryBoard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(SkewTransform.AngleX)" Storyboard.TargetName="Img1Top">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="5"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="10"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="20"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="35"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="60"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="75"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="88"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="Img1Top">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="-2.01"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="-3.45"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="-5.55"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="-7"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-8.75"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="-9.5"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="-8.25"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Img1Top">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="0.90"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0.80"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0.60"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0.40"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0.20"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="0.10"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0.01"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="Img1Top">
<EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="2.5"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="5"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="10.1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="15"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="20"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="22.6"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="24.9"/>
</DoubleAnimationUsingKeyFrames>
<Int32AnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.ZIndex)" Storyboard.TargetName="Img2Bottom">
<EasingInt32KeyFrame KeyTime="0:0:0.8" Value="1"/>
</Int32AnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Img1Top">
<DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(SkewTransform.AngleX)" Storyboard.TargetName="Img2Bottom">
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="-88"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="-75"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-60"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="-35"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="-20"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="-10"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="-5"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Img2Bottom">
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="0.01"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="0.10"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.20"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="0.40"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="0.60"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="0.80"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="0.90"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="Img2Bottom">
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="-9.121"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="-8.87"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-8.564"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="-7"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="-5.438"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="-3.5"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="-2.001"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="Img2Bottom">
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="-24.75"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="-22.5"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-20.062"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="-15.062"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="-10"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="-5.062"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="-2.562"/>
<EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Img2Bottom">
<DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image x:Name="Img2Top" Source="Images/02top.png" Grid.Row="1" Width="70" Height="50" RenderTransformOrigin="0.5,0.5" Margin="0,-1,0,0"/>
<Image x:Name="Img1Top" Source="Images/01top.png" Grid.Row="1" Width="70" Height="50" RenderTransformOrigin="0.5,0.5" Margin="0,-1,0,0">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<Image x:Name="Img2Bottom" Source="Images/02.png" Grid.Row="2" Width="70" Height="50" Visibility="Collapsed" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<Image x:Name="Img1Bottom" Source="Images/01.png" Grid.Row="2" Width="70" Height="50" RenderTransformOrigin="0.5,0.5"/>
<Button Content="Next" HorizontalAlignment="Left" Margin="223.5,5,0,0" Grid.Row="3" VerticalAlignment="Top" Width="70" Click="Button_Click" />
</Grid>
And then on click of the button, you can see the flip.
using System.Windows;
using System.Windows.Media.Animation;
namespace RenderTransformExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
var storyboard = (Storyboard)this.Resources["FlipNumberStoryBoard"];
storyboard.Begin();
}
}
}
Now hooking that up so it just loops through images is up to you.
You can use ScaleTransform to achieve the animation, and some dependency properties to make the UserControl easy to use.
First, you have to display your letter in two halves, which can be done using these styles :
<Style x:Key="UpperHalf" TargetType="ContentControl">
<Style.Setters>
<Setter Property="FontFamily" Value="Courier New" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="RenderTransformOrigin" Value="0.5,1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Border Height="{Binding ElementName=SizeRef,
Path=ActualHeight,
Converter={StaticResource HalfConverter}}"
VerticalAlignment="Top"
Background="{TemplateBinding Background}"
CornerRadius="10,10,0,0"
Padding="10,0">
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<Style x:Key="LowerHalf" TargetType="ContentControl">
<Style.Setters>
<Setter Property="FontFamily" Value="Courier New" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="RenderTransformOrigin" Value="0.5,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Border Height="{Binding ElementName=SizeRef,
Path=ActualHeight,
Converter={StaticResource HalfConverter}}"
VerticalAlignment="Bottom"
Background="{TemplateBinding Background}"
CornerRadius="0,0,10,10"
Padding="10,0">
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock VerticalAlignment="Bottom" Text="{Binding}" />
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Then to display two overlapping letters (the old one and the new one) :
<Grid>
<!-- Hidden textblock, only used for measurement purpose -->
<!-- The border is here to set the total height of the display so that we can have a small space between the two halves -->
<Border Margin="0,1" Visibility="Hidden">
<TextBlock Name="SizeRef"
Margin="10,0"
FontFamily="Courier New"
Text="{Binding ElementName=Root,
Path=Letter}" />
</Border>
<ContentControl Name="Letter1Top"
Background="Gray"
Content="{Binding ElementName=Root,
Path=Letter1}"
Style="{StaticResource UpperHalf}">
<ContentControl.RenderTransform>
<ScaleTransform />
</ContentControl.RenderTransform>
</ContentControl>
<ContentControl Name="Letter2Top"
Background="Gray"
Content="{Binding ElementName=Root,
Path=Letter2}"
Style="{StaticResource UpperHalf}">
<ContentControl.RenderTransform>
<ScaleTransform />
</ContentControl.RenderTransform>
</ContentControl>
<ContentControl Name="Letter1Bottom"
Background="Gray"
Content="{Binding ElementName=Root,
Path=Letter1}"
Style="{StaticResource LowerHalf}">
<ContentControl.RenderTransform>
<ScaleTransform />
</ContentControl.RenderTransform>
</ContentControl>
<ContentControl Name="Letter2Bottom"
Background="Gray"
Content="{Binding ElementName=Root,
Path=Letter2}"
Style="{StaticResource LowerHalf}">
<ContentControl.RenderTransform>
<ScaleTransform />
</ContentControl.RenderTransform>
</ContentControl>
</Grid>
The properties used above are created in code behind :
public partial class SplitFlapLetter
{
public SplitFlapLetter()
{
InitializeComponent();
}
public char Letter
{
get { return (char)GetValue(LetterProperty); }
set { SetValue(LetterProperty, value); }
}
public static readonly DependencyProperty LetterProperty =
DependencyProperty.Register("Letter", typeof(char), typeof(SplitFlapLetter), new UIPropertyMetadata(OnLetterChanged));
private char Letter1
{
get { return (char)GetValue(Letter1Property); }
set { SetValue(Letter1Property, value); }
}
public static readonly DependencyProperty Letter1Property =
DependencyProperty.Register("Letter1", typeof(char), typeof(SplitFlapLetter), new UIPropertyMetadata(null));
private char Letter2
{
get { return (char)GetValue(Letter2Property); }
set { SetValue(Letter2Property, value); }
}
public static readonly DependencyProperty Letter2Property =
DependencyProperty.Register("Letter2", typeof(char), typeof(SplitFlapLetter), new UIPropertyMetadata(null));
private bool _isLetter1Active;
private static void OnLetterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uc = d as SplitFlapLetter;
if (uc == null) return;
if (uc._isLetter1Active)
uc.Letter2 = uc.Letter;
else
uc.Letter1 = uc.Letter;
var sb = uc.FindResource(uc._isLetter1Active ? "GotoLetter2Animation" : "GotoLetter1Animation") as Storyboard;
if (sb != null) sb.Begin();
uc._isLetter1Active = !uc._isLetter1Active;
}
private readonly List<char> _letters = new List<char> { 'A', 'B', 'C', 'D', 'E' };
private void OnClick(object sender, MouseButtonEventArgs e)
{
Letter = _letters[(_letters.IndexOf(Letter) + 1) % _letters.Count];
}
}
The Letter property is the only public one and there is a listener on its changes.
This listener sets Letter1 or Letter2 to the new value, changing at every run, so that the other property is still set to the old value.
It then starts one of the two storyboard defined in the UserControl resources :
<Storyboard x:Key="GotoLetter1Animation">
<DoubleAnimation Duration="0:0:0"
Storyboard.TargetName="Letter1Bottom"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="0" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter2Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="2" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter2Bottom"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="1" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter1Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="1" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter1Bottom"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="2" />
<DoubleAnimation Duration="0:0:0.2"
From="1"
Storyboard.TargetName="Letter2Top"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="0" />
<DoubleAnimation BeginTime="0:0:0.2"
Duration="0:0:0.2"
From="0"
Storyboard.TargetName="Letter1Bottom"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="1" />
<Int32Animation BeginTime="0:0:0.4"
Duration="0:0:0"
Storyboard.TargetName="Letter1Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="2" />
<Int32Animation BeginTime="0:0:0.4"
Duration="0:0:0"
Storyboard.TargetName="Letter2Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="1" />
<DoubleAnimation BeginTime="0:0:0.4"
Duration="0:0:0"
Storyboard.TargetName="Letter2Top"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="1" />
</Storyboard>
<Storyboard x:Key="GotoLetter2Animation">
<DoubleAnimation Duration="0:0:0"
Storyboard.TargetName="Letter2Bottom"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="0" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter1Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="2" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter1Bottom"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="1" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter2Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="1" />
<Int32Animation Duration="0:0:0"
Storyboard.TargetName="Letter2Bottom"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="2" />
<DoubleAnimation Duration="0:0:0.2"
From="1"
Storyboard.TargetName="Letter1Top"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="0" />
<DoubleAnimation BeginTime="0:0:0.2"
Duration="0:0:0.2"
From="0"
Storyboard.TargetName="Letter2Bottom"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="1" />
<Int32Animation BeginTime="0:0:0.4"
Duration="0:0:0"
Storyboard.TargetName="Letter2Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="2" />
<Int32Animation BeginTime="0:0:0.4"
Duration="0:0:0"
Storyboard.TargetName="Letter1Top"
Storyboard.TargetProperty="(Panel.ZIndex)"
To="1" />
<DoubleAnimation BeginTime="0:0:0.4"
Duration="0:0:0"
Storyboard.TargetName="Letter1Top"
Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
To="1" />
</Storyboard>
There's probably some way to reduce this xaml and use only one storyboard that would uses the appropriate targets.
I think that this project could really give you a base for what you want to do.
Unfortunately, I don't see how this split-flap display could look well without 3D.
Good luck !

Categories