Move&Zoom Image - c#

I have a pretty simple requirement (I thought), a window that shows an image at a certain start point & size and moves/zooms it to a certain end point and size. This is not the typical Image Viewer requirement for pan&zoom. More like a sprite animation.
I tried out a couple of ways, e.g. a ThicknessAnimation to alter the Margin to move the image, but the performance was just not good enough. I have to admit I don't have much experience with WPF, though.
Below is my last version which is ok performance-wise. The image element goes over the whole window and the size and position are set by ScaleTransform and TranslateTransform. It works well (and shows relatively smooth movement) if the end position is on the lower right of the start position, e.g. from 0,0 to 800,600. If it's the other way around, though, the image makes kind of a slingshot movement to the lower right corner of the window, leaves the window and then finally comes back to stop at its end position.
I would appreciate an explanation for this behavior as well as a solution. And if you know a different way that works and is similar or better performance-wise, I'd like to hear that too.
<Window x:Class="ViewBoxText.AnimatedImageWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AnimatedImageWindow"
WindowStyle="None"
SizeToContent="WidthAndHeight"
AllowsTransparency="True"
ShowInTaskbar="False"
Left="0"
Top="0"
Height="{Binding TotalHeight}"
Width="{Binding TotalWidth}"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Image x:Name="image" HorizontalAlignment="Left" VerticalAlignment="Top" Width="{Binding TotalWidth}" Height="{Binding TotalHeight}" Stretch="Uniform">
<Image.RenderTransform>
<TransformGroup>
<TranslateTransform X="{Binding HorizontalStart}" Y="{Binding VerticalStart}" />
<ScaleTransform />
</TransformGroup>
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Image.Loaded">
<BeginStoryboard>
<Storyboard Completed="OnStoryBoardCompleted">
<DoubleAnimation Storyboard.TargetName="image"
Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleX)"
From="{Binding ScaleStart}" To="{Binding ScaleEnd}" DesiredFrameRate="30"
Duration="0:0:2" BeginTime="0:0:0" />
<DoubleAnimation Storyboard.TargetName="image"
Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[1].(ScaleTransform.ScaleY)"
From="{Binding ScaleStart}" To="{Binding ScaleEnd}" DesiredFrameRate="30"
Duration="0:0:2" BeginTime="0:0:0" />
<DoubleAnimation Storyboard.TargetName="image"
Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"
By="{Binding HorizontalOffset}"
Duration="0:0:2" BeginTime="0:0:0" />
<DoubleAnimation Storyboard.TargetName="image"
Storyboard.TargetProperty="(Image.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.Y)"
From="{Binding VerticalStart}" To="{Binding VerticalEnd}"
Duration="0:0:2" BeginTime="0:0:0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
</Grid>

The problem is the scale is scaling about 0,0. I believe you want to scale about the point you are interested in, which may or may not be you Vertical/Horizontal end point.
Normally, you would translate so that the centre is on the origin, scale, then put the whole thing back.
e.g. to scale by X about point A,B
Translate -A,-B
Scale X
Translate A,B
Fortunately the scale has a couple of centre properties that make this easier.
So try adjusting the CenterX and CenterY properties of the ScaleTransform.

Related

Scrolling NewsTicker is cutting off early

I have a scrolling News Ticker in WPF that is used to convey alerts (their preference not mine). The implementation works but I have found an issue which is more noticeable as the text gets longer. The text scrolls and then abruptly stops and then restarts.
<Border Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="5" BorderBrush="White" BorderThickness="0,3,0,3">
<StackPanel Orientation="Horizontal" x:Name="Ticker" Background="Transparent" >
<StackPanel.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard x:Name="NewsTicker">
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation From="{Binding ElementName=Ticker, Path=ActualWidth}" To="{Binding ElementName=Ticker, Path=ActualWidth, Converter={StaticResource NegConverter}}" Storyboard.TargetName="translate" Storyboard.TargetProperty="X" Duration="0:0:35" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="WrapPanel.MouseEnter">
<PauseStoryboard BeginStoryboardName="NewsTicker" />
</EventTrigger>
<EventTrigger RoutedEvent="WrapPanel.MouseLeave">
<ResumeStoryboard BeginStoryboardName="NewsTicker" />
</EventTrigger>
</StackPanelPanel.Triggers>
<TextBlock Text="{Binding NewsTicker, IsAsync=True}" Margin="0,0,0,0" Padding="0,0,0,0" VerticalAlignment="Top" >
<TextBlock.RenderTransform>
<TranslateTransform x:Name="translate" />
</TextBlock.RenderTransform>
</TextBlock>
</StackPanelPanel>
</Border>
I would like the text to scroll from the Right to the Left until it scrolls off the screen and then come back in once again from the Right in an endless loop.
I tried a couple of different methods from SO, including animating Margins with Thickness animation and as well as an example using a canvas, but neither of them actually worked at all.
Any advice?
Okay, so the key to it not jumping is binding to the right things - we want to bind the To field to the ActualWidth of the TextBlock, not the ActualWidth of the StackPanel (which is smaller)
So we can change the DoubleAnimation to:
<DoubleAnimation From="{Binding ElementName=Ticker, Path=ActualWidth}" To="{Binding ElementName=TickerTextBlock, Path=ActualWidth, Converter={StaticResource NegConverter}}" Storyboard.TargetName="translate" Storyboard.TargetProperty="X" Duration="0:0:4" />
And add a x:Name="TickerTextBlock" to the TextBlock containing the Text.
Unfortunately, this doesn't work straight off (and instead it uses the initial value of 0 from the binding pre text loading for the animation! :|). Animations are often very fickle like this - I believe it has something to do with only being created and run once, and so the value of the binding is only used when the animation is first run. (but I may be mis-understanding)
Certainly one solution which worked on my copy of your code is to ensure that the text loads first, (ie we place the TextBlock above the animation in the XAML, and change the binding so that it is not async.)
If you wish to keep the async, then I believe we'd need to restart the double animation when the text changes. I would look into this further, but it's really late and I'm going to head to bed (sorry!)

How can I make a bouncing label in WPF xaml? (C#)

I'm stuck with my school assignment and it should be ready soon, so I hope someone could help me. I've been searching for a solution for hours. I'm sure this is a very simple thing, but I just can't figure it out.
So I'm trying to make a label move in a specific area so that it bounces from "borders" (an area defined with From/To) and takes a new direction. So far I have only managed to make it move up and down, left and right or from corner to corner, but not in every direction. I have no idea how I'm supposed to implement this. This is my xaml code:
<Canvas Height="60" HorizontalAlignment="Left" Margin="138,0,0,0" Name="canvas1" VerticalAlignment="Top" Width="227">
<Label Content="GKO" Height="40" Name="labelGKO" Canvas.Left="19" Canvas.Top="6" Width="61" FontSize="8">
<Label.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard TargetName="labelGKO" RepeatBehavior="Forever">
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Left)"
From="0" To="180" Duration="0:0:1"/>
<DoubleAnimation
Storyboard.TargetProperty="(Canvas.Top)"
From="0" To="50" Duration="0:0:1"
AutoReverse="True" />
<DoubleAnimation
Storyboard.TargetProperty="(Label.FontSize)"
To="24" Duration="0:0:1"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Label.Triggers>
</Label>
</Canvas>
This makes the label move from up left corner to the bottom right and then up. Then it starts from the beginning. It is clear I don't understand the logic behind it. Should I do multiple Storyboards or DoubleAnimations? Or can I somehow change the course of the label during one animation? How can I tell the label where exactly to go after it has reached a border?

Rotate an Image around a point i Windows 8 metro

I want to rotate a image around a point using the flick speed of the user and it should slow down as rotates and the effect should be natural ...
till now I have tried to achieve this using storyboard but was not getting the desired result as the speed of the user can be variable. I have also tried using update loop but I am not able understand how to achieve it.
I want this start arrow to rotate around the nail.
ant help will be appreciated ... thanx
You can use RotateTransform and set centerx centery to nail position: Then bind Angle to some value and change it to any value you want.
<Image.RenderTransform>
<RotateTransform Angle="{Binding RotationAngle}" CenterX="10" CenterY="10" />
</Image.RenderTransform>
Or instead of binding you can use storyboard to change angle (change rectangle controll to image)
<Rectangle Width="40" Height="40" Fill="Orange">
<Rectangle.RenderTransform>
<RotateTransform x:Name="Rotation" CenterX="10" CenterY="10" />
</Rectangle.RenderTransform>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Rotation"
Storyboard.TargetProperty="Angle"
From="1.0" To="40.0" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>

How to start a storyboard which is attached to a control inside a data template?

I have a storyboard inside a data template. I want to start this only for a certain condition. In my case whenever the no. of seconds in the clock is 59 the storyboard should start.
Below you can see the storyboard as well as the control to which the animation is applied :
<!-- Minute Hand -->
<Image
Source="{Binding Time, Converter={StaticResource MinHandBackground}}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Canvas.Left="118"
Canvas.Top="118">
<Image.RenderTransform>
<TransformGroup>
<TranslateTransform
X="-11"
Y="-90" />
<RotateTransform
x:Name="minHandTransform" />
</TransformGroup>
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger
RoutedEvent="Image.Loaded">
<BeginStoryboard>
<Storyboard
x:Name="myStoryboard2">
<DoubleAnimation
x:Name="minuteAnimation"
Storyboard.TargetName="minHandTransform"
Storyboard.TargetProperty="Angle"
Duration="0:0:1"
From="{Binding Time, Converter={StaticResource minuteHandTransform}}"
To="{Binding Time, Converter={StaticResource minuteHandToTransform}}"
RepeatBehavior="1x">
<DoubleAnimation.EasingFunction>
<SineEase
EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
Currently the BeginStoryboard starts it immediately on load. I want to start it when the number of seconds is 59 but i cant access the storyboard in the back end as the control is within a data template.
Can anyone please help me out here.....i have been banging my head about this problem for a lot of days now!!
The easiest way would be to move the entire contents of the DataTemplate to a separate UserControl so you would get easier access to all named elements.

How to enlarge a picture in WPF?

I have to enlarge a single picture in WPF. The problem is that after the operation the picture is shown only a part.
And I have to make it enlarged gradually. How can I do it?
I think that you modified image stretch property to none.
Set Height and Width attributes:
<Image
Height="165"
HorizontalAlignment="Left"
Name="image1" Stretch="Fill"
VerticalAlignment="Top"
Width="339"
Source="[your source]" />
In [your source] you will put your image's source.
If your image element is showing only part of the picture, you can change the Stretch property to either Uniform, which preserves the aspect ratio, or Fill, which does not.
You can use a ScaleTransform for the RenderTransform property to enlarge the picture without affecting the layout of your application or a ScaleTransform for the LayoutTransform property to enlarge the picture so your layout is affected. ScaleTransform provides two important properties, ScaleX and ScaleY, which affect how the image is resized in its X and Y axes, respectively. To apply this effect gradually, you must use a DoubleAnimation. You don't specify when you want to trigger the enlargement, so for the purpose of example, I'll assume you want the image to be enlarged when the user mouses over the image. The provided code also gradually decreases the image size when the user mouses out of the image. To change when the increase and decrease of size occurs, change the RoutedEvent property of the two EventTriggers.
<Image Stretch="Uniform" Source="Penguins.jpg">
<Image.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1" x:Name="scale" />
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="ScaleX"
Storyboard.TargetName="scale" To="1.5"
Duration="0:0:1" />
<DoubleAnimation Storyboard.TargetProperty="ScaleY"
Storyboard.TargetName="scale" To="1.5"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="ScaleX"
Storyboard.TargetName="scale" To="1"
Duration="0:0:1" />
<DoubleAnimation Storyboard.TargetProperty="ScaleY"
Storyboard.TargetName="scale" To="1"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>

Categories

Resources