How To Rotate an Image using a StoryBoard - wpf

I am trying to rotate an image and want to use a storyboard as in the next phases i need to add multiple animations running to time.
my code is inside a click event of a button as follows:
//start the animation
DoubleAnimation animationRotation = new DoubleAnimation();
animationRotation.From = -17;
animationRotation.To = 17;
animationRotation.Duration = new Duration(TimeSpan.FromMilliseconds(NumericDisplay.Milliseconds));
animationRotation.RepeatBehavior = RepeatBehavior.Forever;
animationRotation.AccelerationRatio = 0.3;
animationRotation.DecelerationRatio = 0.3;
animationRotation.AutoReverse = true;
Storyboard storyboard = new Storyboard();
Storyboard.SetTarget(animationRotation, Arm);
Storyboard.SetTargetProperty(animationRotation,
new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));
storyboard.Children.Add(animationRotation);
// Add the storyboard to the tracking collection.
//this.Stostoryboards.Add(bomb, storyboard);
// Configure and start the storyboard.
this.BeginStoryboard(storyboard);
the code compiles without warning yet the click event does not start the animation,
EDIT
One of the proposed answers asked me to check the XAML included a definition for rotatetransform ... the XAML below is what I am using
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
<ImageBrush x:Key="ImageBrush_Decrement" ImageSource="Images/pad-metronome-decrement-button.png" Stretch="Fill"/>
<ImageBrush x:Key="ImageBrush_Increment" ImageSource="Images/pad-metronome-increment-button.png" Stretch="Fill"/>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
</EventTrigger>
</UserControl.Triggers>
<Grid x:Name="LayoutRoot" Height="412">
<Image x:Name="MetronomeWindowBackground" Height="140" Margin="237,1.5,231,0" Source="Images\pad-metronome-top-under-bg.png" Stretch="Fill" VerticalAlignment="Top"/>
<Image x:Name="Arm" Margin="506,17,493,0" Source="Images\pad-metronome-arm.png" Stretch="Fill" Height="326" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<RotateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
<Image x:Name="MetronomeFlash" Height="209" Margin="104,0,96,0" Source="Images\pad-metronome-flash-top-landscape.png" Stretch="Fill" VerticalAlignment="Top" d:IsHidden="True" />
<Image x:Name="MetronomeBackground" Height="209" Source="Images\pad-metronome-top-bg-landscape.png" Stretch="Fill" VerticalAlignment="Top" Margin="3,0,-3,0"/>
<Image x:Name="MetronomeStartButton" Margin="379.5,100.5,373.5,0" Source="Images\pad-metronome-start-button-base.png" Stretch="Fill" Height="110" VerticalAlignment="Top"/>
<Image x:Name="MetronomeTapPadLeft" HorizontalAlignment="Left" Height="209" Margin="5,1.5,0,0" Source="Images\pad-metronome-tap-pad-left.png" Stretch="Fill" VerticalAlignment="Top" Width="136"/>
<Image x:Name="MetronomeTapPadRight" HorizontalAlignment="Right" Source="Images\pad-metronome-tap-pad-right.png" Stretch="Fill" Width="136" Height="209" VerticalAlignment="Top"/>
<Image x:Name="MetronomeWindowHighlight" Height="105" Margin="238.5,18,231.5,0" Source="Images\pad-metronome-window-overlay.png" Stretch="Fill" VerticalAlignment="Top"/>
<Image x:Name="MetronomeBottomBackground" Margin="3,208,-3,362" Source="Images\pad-metronome-section-bottom-bg.png" Stretch="Fill"/>
<my:MetronomeLargeNumericDisplay HorizontalAlignment="Left" Margin="459,120,0,0" x:Name="NumericDisplay" VerticalAlignment="Top" Value="999" Width="122.25" />
<Image Height="78" Margin="448,110.5,436,0" Source="Images\pad-metronome-start-button-overlay.png" Stretch="Fill" VerticalAlignment="Top"
x:Name="DisplayOverlay" MouseDown="DisplayOverlay_MouseDown" />
<RepeatButton x:Name="ButtonDecrement" Content="" BorderThickness="7" HorizontalAlignment="Left" Margin="252,110.5,0,0" VerticalAlignment="Top" Width="149" Height="100" Background="{DynamicResource ImageBrush_Decrement}" Style="{DynamicResource RepeatButtonStyle_noflash}" BorderBrush="{DynamicResource ImageBrush_Decrement}" d:LayoutOverrides="HorizontalAlignment" Click="ButtonDecrement_Click"></RepeatButton>
<RepeatButton Content="" BorderThickness="7" HorizontalAlignment="Left" Margin="631,110.5,0,0" VerticalAlignment="Top" Width="149" Height="100" Background="{DynamicResource ImageBrush_Increment}" Style="{DynamicResource RepeatButtonStyle_noflash}" BorderBrush="{DynamicResource ImageBrush_Decrement}" Name="ButtonIncrement" Click="ButtonIncrement_Click" />
</Grid>
what am I doing wrong?

The code you've posted seems to be ok, however, the path refers to an existing element, so make sure you've included appropriate nodes in xaml, where Arm control is defined.
Let's say Arm is a Rectangle control. Your xaml should then look more or less like this:
...
<Rectangle x:Name="Arm" Fill="Aqua" Width="100" Height="100" Canvas.Left="100" Canvas.Top="100">
<Rectangle.RenderTransform>
<TransformGroup>
<RotateTransform />
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
...
Arm can be another type of control, but the important thing is that RenderTransform, TransformGroup and RotateTransform nodes are defined, so animation has some existing elements to change as specified in the PropertyPath in your code.

after much messing around with new projects and much simplified code I asked the question slightly differently in another thread and someone posted working code.
on investigation that reason my animation was not working was that I had provided a duration to the animation but not the storyboard itself !! doh.
full answer here (which is one of the fullest answers I have received on this topic)
How do I create a rotate animation on an image object using c# code only (inside a WPF window)
Lucas, thanks to you for your patience and assistance on this question.
Dan

Related

How to tint an Image in wpf?

here I have an image (I want to display it as an icon in my list).
and I have to change its color when it's selected.
I tried this solution before:
https://stackoverflow.com/a/42794551/14564778
With this codes:
<Grid Margin="5,0,0,0">
<Image Height="25" Width="25" Source="{Binding ItemImageSource}" RenderOptions.BitmapScalingMode="Fant"/>
<Rectangle Height="25" Width="25" Fill="{StaticResource orangePink}" RenderOptions.BitmapScalingMode="Fant">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="{Binding ItemImageSource}"/>
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
The problem I got is the shape of the image is not consistent when I apply the new color
Note that the images that I use are high resolution images.
so, If anyone can help me with codes or third-party library or another way.
I will be happy for this.
thx...

WPF / Xaml, vertical aligment of LineGeomtry inside grid not working properly

I try to get into creation of custom controls with for WPF. I found many good
tutorials and advises on the web so I started width a really simple example to get
my hands dirty and get some practice. I figured out that the issue stumbled across
is not really related to the subject of custom controls. So I extracted the xaml code to a simple wpf form.
<Window x:Class="WpfVerticalAigmentTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="200">
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20" VerticalAlignment="Center" >
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="100,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
</Grid>
My expectation was to get a line centered in the grid and claiming the half of the stroke thickness on each side from the center. But as the linked image shows differs from my expectation.
"Resulting visualization"
So it look like I missed a detail about the line shape or linegeomtry. How do I get the the line displayed as shown in the following image?
"Expected result"
You need to match the Width and Height of the LineGeometry to the Width and Height of the Path and set the VerticalAlignment property to Bottom:
<Grid Height="20" Width="200" Background="LightCyan" VerticalAlignment="Center">
<Path Stroke="Red" StrokeThickness="20" VerticalAlignment="Bottom">
<Path.Data>
<LineGeometry StartPoint="0,0" EndPoint="200,0"></LineGeometry>
</Path.Data>
</Path>
</Grid>
If your goal is your the expectaions, and not the way how u have reached this, I could prefer to you this:
<Grid>
<Grid Height="40" Background="LightCyan" VerticalAlignment="Center">
<Border BorderThickness="10" VerticalAlignment="Center" BorderBrush="Red" />
</Grid>
</Grid>
The problem here is that the starting point of the XY Coordinates of the Path starts on the top left, and the stroke expands in both directions but thereby only makes the Path bigger to the bottom (I can't really tell you why, but that's just what seems to happen).
You can see this pretty good in the Design View:
To work around this simply move your Y Coordinates down half of the stroke size.
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Path VerticalAlignment="Center"
Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Grid>
Or wrap it in another control (Canvas is the commonly used controls for Paths) with the desired height:
<Grid Height="40"
VerticalAlignment="Center"
Background="LightCyan">
<Canvas Height="20" VerticalAlignment="Center">
<Path Stroke="Red"
StrokeThickness="20">
<Path.Data>
<LineGeometry StartPoint="0,10" EndPoint="100,10" />
</Path.Data>
</Path>
</Canvas>
</Grid>
And you are good to go:

Canvas as Image in Button WPF

I am in the process of moving all images from our project into a ResourceDictionary to be used across all projects. When using Syncfusion Metro Studio I am able to get the XAML source of the images.
<Viewbox x:Shared="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid>
<Grid Name="backgroundGrid" Width="48" Height="48" Visibility="Collapsed" />
<Path Data="M0,4.1309996L20.362437,4.1309996C20.038338,4.8125897,19.782439,5.5301299,19.594339,6.2769008L2.1451931,6.2769008 2.1451931,23.445208 30.042807,23.445208 30.042807,20.78887C30.342306,20.81167 30.642406,20.834471 30.949104,20.834471 31.367603,20.834471 31.781102,20.81027 32.188001,20.76737L32.188001,25.590239 20.922435,25.590239 20.922435,27.736771 23.605427,27.736771 23.605427,29.882 8.5839529,29.882 8.5839529,27.736771 11.265565,27.736771 11.265565,25.590239 0,25.590239z M29.967411,3.9921243L29.967411,8.1359167 25.823251,8.1359167 25.823251,10.100034 29.967411,10.100034 29.967411,14.243865 31.931586,14.243865 31.931586,10.100034 36.075645,10.100034 36.075645,8.1359167 31.931586,8.1359167 31.931586,3.9921243z M30.948448,0C35.985142,1.0841802E-08 40.067997,4.0825729 40.067997,9.1171007 40.067997,14.153367 35.985142,18.236 30.948448,18.236 25.912456,18.236 21.830998,14.153367 21.830998,9.1171007 21.830998,4.0825729 25.912456,1.0841802E-08 30.948448,0z" Stretch="Uniform" Fill="#FF666666" Width="26" Height="26" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<TransformGroup.Children>
<RotateTransform Angle="0" />
<ScaleTransform ScaleX="1" ScaleY="1" />
</TransformGroup.Children>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
</Viewbox>
The issue here is that I am creating buttons with the image next to my text as follows:
<corecontrols:IdyllicButton Name="btnClose" Height="30">
<StackPanel Orientation="Horizontal">
<Image Source="/MHA.Modules.PolicyAdmin;component/Images/Cancel.png"/>
<TextBlock VerticalAlignment="Center" Margin="5,0" Text="Close"/>
</StackPanel>
</corecontrols:IdyllicButton>
But I cannot set my Image.ImageSource to my StaticResource that I have created in a ResourceDictionary as I get the following error:
An object of the type "System.Windows.Controls.Viewbox" cannot be
applied to a property that expects the type
"System.Windows.Media.ImageSource".
I have also tried using a canvas.
Any ideas how to do this?
Hoping this helps someone:
I found the solution, instead of using a Image, use the Rectangle control in its place and set the OpacityMask to the Viewbox resource.
<Rectangle Width="15" VerticalAlignment="Center"
Height="15"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Uniform" Visual="{StaticResource Close}"/>
</Rectangle.OpacityMask>
</Rectangle>
I found this scrolling MahApps.Metro source code for the WindowCommand Buttons.

Image Rotation inside WP7 Scrollviewer

In an Windows Phone 7 application, I want to apply a 90ยบ rotation to an image when the user clicks a button. I'm doing the following:
<Image Height="369" Name="imageView" Stretch="Uniform" Width="394">
<Image.RenderTransform>
<RotateTransform Angle="0" />
</Image.RenderTransform>
</Image>
At the function:
((RotateTransform)imageView.RenderTransform).Angle += 90;
So far, so good. The problem appears when I place the image within a scrollviewer.
<ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible" Height="389" HorizontalAlignment="Left" Margin="12,78,0,0" Name="scrollViewer" VerticalAlignment="Top" Width="409">
<Image Height="369" Name="imageView" Stretch="Uniform" Width="394">
<Image.RenderTransform>
<RotateTransform Angle="0" />
</Image.RenderTransform>
</Image>
</ScrollViewer>
In this case I get an error - InvalidCastException was unhandled - on this line of code:
((RotateTransform)imageView.RenderTransform).Angle += 90;
The problem is that imageView.RenderTransform is not a RotateTransform then, but of CompositeTransform instead, so try this instead:
((CompositeTransform)imageView.RenderTransform).Rotation += 90;
And if you want to specify it as a Composite transform directly in the XAML too, you can do that:
<ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible" Height="389" HorizontalAlignment="Left" Margin="12,78,0,0" Name="scrollViewer" VerticalAlignment="Top" Width="409">
<StackPanel>
<Image Height="369" Name="imageView" Stretch="Uniform" Width="394" Source="/PhoneApp2;component/Images/lumia-920-rainbow.png">
<Image.RenderTransform>
<CompositeTransform Rotation="0" CenterX="197" CenterY="184" />
</Image.RenderTransform>
</Image>
<StackPanel>
</ScrollViewer>

ScaleTransform and CenterX

I have the following code
<Canvas Width="800" Height="600">
...
<local:UpgradeLandDialog x:Name="upgradeDialog" Canvas.Left="250" Canvas.Top="200" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0">
<local:UpgradeLandDialog.LayoutTransform>
<ScaleTransform ScaleX="0" ScaleY="0" CenterX="400" CenterY="300"/>
</local:UpgradeLandDialog.LayoutTransform>
</local:UpgradeLandDialog>
</Canvas>
In the UserControl I animate the ScaleTranform to 1. I want UserControl to "grow" from its center, but it "grows" from the upper left corner of it. The values in CenterX and CenterY do nothing. How can I make it Scale as I want?
You can use RenderTransformOrigin="0.5,0.5" on the control you want to animate.
You can change your code like this:
<Canvas Width="800" Height="600" RenderTransformOrigin="0.5,0.5">
<local:UpgradeLandDialog x:Name="upgradeDialog" Canvas.Left="250" Canvas.Top="200" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0">
<local:UpgradeLandDialog.LayoutTransform>
<ScaleTransform ScaleX="0" ScaleY="0"/>
</local:UpgradeLandDialog.LayoutTransform>
</local:UpgradeLandDialog>
</Canvas>
Remove (CenterX="400" CenterY="300") and add (RenderTransformOrigin="0.5,0.5") to the Canvas. This way if you have a container with dynamic width and height, it can scale from the center without problem.
To make it grow from its center, you'll have to animate its margins as well (at half the rate at which you animate the width and height).
I ran into this problem not too long ago as well. I ended up repositioning the user control at every layout update to simulate a custom point based growth.
This does work for me. Did I miss something?
<Rectangle StrokeThickness="1" Stroke="Black" Width="200" Height="200">
<Rectangle.RenderTransform>
<ScaleTransform
ScaleX="{Binding ElementName=slider, Path=Value}"
ScaleY="{Binding ElementName=slider, Path=Value}"
CenterX ="100" CenterY="100"/>
</Rectangle.RenderTransform>
</Rectangle>
Even though this is an old post, I thought I'd share my findings, since it took me way too long to figure out this fairly simple solution.
Flipping the y-axis was easy, but I couldn't get CenterX and CenterY working. I really needed to be able to set the origin at any position I wanted.
Solution: nested canvasses.
<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Canvas Canvas.Left="{Binding MyOriginLeft}" Canvas.Bottom="{Binding MyOriginBottom}">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="-1"/>
</Canvas.LayoutTransform>
<!-- This now does what you expect it to do, independent of position of origin -->
<Line X1="10" Y1="20" X2="30" Y2="40" Stroke="Black" StrokeThickness="1"/>
</Canvas>
</Canvas>

Resources