Infinitely rotate rectangle in XAML - wpf

How to define XAML to rotate a rectangle infinitely?
So far I found a solution with code but no xaml:
http://www.codeproject.com/Articles/23257/Beginner-s-WPF-Animation-Tutorial
which I use like this:
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
var doubleAnimation = new DoubleAnimation(360, 0, new Duration(TimeSpan.FromSeconds(1)));
var rotateTransform = new RotateTransform();
rect1.RenderTransform = rotateTransform;
rect1.RenderTransformOrigin = new Point(0.5, 0.5);
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
rotateTransform.BeginAnimation(RotateTransform.AngleProperty, doubleAnimation);
}
But how can I achieve this with XAML only?

Something like this
<Rectangle x:Name="rect1" RenderTransformOrigin="0.5, 0.5">
<Rectangle.RenderTransform>
<!-- giving the transform a name tells the framework not to freeze it -->
<RotateTransform x:Name="noFreeze" />
</Rectangle.RenderTransform>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Rectangle.RenderTransform).(RotateTransform.Angle)"
To="-360" Duration="0:0:1" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Of course you can remove Loaded trigger and run this storyboard whenever you want.

Related

Morph a shape in WPF

I want to animate the form o a circle into a square. The same way we did it in the flash animations time, but in WPF.
I'm open to any suggestion on how to approach it. I do have my path data for the final and initial shapes but I cannot find anything relevant.
My google search only go into the directions of animating a form along a path. This is not what I want, I want my object to stay stationary but change it outline from a circle to a square.
You could animate the RadiusX and RadiusY properties of a Rectangle like this:
<Rectangle Width="100" Height="100" RadiusX="50" RadiusY="50"
Stroke="Red" StrokeThickness="3">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard BeginTime="0:0:2">
<DoubleAnimation
Storyboard.TargetProperty="RadiusX"
To="0" Duration="0:0:2"/>
<DoubleAnimation
Storyboard.TargetProperty="RadiusY"
To="0" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
Alternatively, animate the CornerRadius of a Border with a custom animation:
<Border Width="100" Height="100" CornerRadius="50"
BorderBrush="Red" BorderThickness="3">
<Border.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard BeginTime="0:0:2">
<local:CornerRadiusAnimation
Storyboard.TargetProperty="CornerRadius"
To="0" Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>
The CornerRadiusAnimation:
public class CornerRadiusAnimation : AnimationTimeline
{
public CornerRadius To { get; set; }
public override Type TargetPropertyType
{
get { return typeof(CornerRadius); }
}
protected override Freezable CreateInstanceCore()
{
return new CornerRadiusAnimation { To = To };
}
public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
{
if (!animationClock.CurrentProgress.HasValue)
{
return defaultOriginValue;
}
var p = animationClock.CurrentProgress.Value;
var from = (CornerRadius)defaultOriginValue;
return new CornerRadius(
(1 - p) * from.TopLeft + p * To.TopLeft,
(1 - p) * from.TopRight + p * To.TopRight,
(1 - p) * from.BottomRight + p * To.BottomRight,
(1 - p) * from.BottomLeft + p * To.BottomLeft);
}
}

Drag over effect using XAML

I am trying to change Background of a Border when user is dragging a file on it.
I want to define the effect using XAML only.
I tried the below but the Background is not changed when dragging a file on the Border.
<Border Name="dropBorder" BorderThickness="1" AllowDrop="True">
<Border.Triggers>
<EventTrigger RoutedEvent="DragOver">
<BeginStoryboard>
<Storyboard Storyboard.TargetProperty="Background">
<ColorAnimation From="Transparent" To="#FF444444" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<TextBlock Text="Drag and drop file(s) here" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10"/>
</Border>
I also tried to use DragEnter as below with no results
<EventTrigger RoutedEvent="Border.DragEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="dropBorder"
Storyboard.TargetProperty="Background"
Duration="0:0:0.5"
From="Transparent" To="#FF444444"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
I didnt quite meet your 100% requirement. I created an attached property, which I set via code-behind, so you will want to assess this. Also, moved the color animation around as you were trying to animate a brush, not a color.
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<SolidColorBrush x:Key="SharedBackgroundBrush" Color="Transparent" />
</Window.Resources>
<Border Name="dropBorder" BorderThickness="1" AllowDrop="True" DragEnter="DropBorder_OnDragEnter" DragLeave="DropBorder_OnPreviewDragLeave" Background="{StaticResource SharedBackgroundBrush}">
<Border.Style>
<Style>
<Style.Triggers>
<Trigger Property="wpfApplication1:DragDropHelper.IsDragOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard Storyboard.Target="{StaticResource SharedBackgroundBrush}" Storyboard.TargetProperty="Color">
<ColorAnimation From="Transparent" To="Yellow" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard Storyboard.Target="{StaticResource SharedBackgroundBrush}" Storyboard.TargetProperty="Color">
<ColorAnimation From="Yellow" To="Transparent" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="Drag and drop file(s) here" Foreground="Gray" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10"/>
</Border>
</Window>
Code:
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void DropBorder_OnDragEnter(object sender, DragEventArgs e)
{
DragDropHelper.SetIsDragOver((DependencyObject)sender, true);
}
private void DropBorder_OnPreviewDragLeave(object sender, DragEventArgs e)
{
DragDropHelper.SetIsDragOver((DependencyObject)sender, false);
}
}
public class DragDropHelper
{
public static readonly DependencyProperty IsDragOverProperty = DependencyProperty.RegisterAttached(
"IsDragOver", typeof (bool), typeof (DragDropHelper), new PropertyMetadata(default(bool)));
public static void SetIsDragOver(DependencyObject element, bool value)
{
element.SetValue(IsDragOverProperty, value);
}
public static bool GetIsDragOver(DependencyObject element)
{
return (bool) element.GetValue(IsDragOverProperty);
}
}
}

WPF Storyboard - same trigger, but reverse behavior

I have a Stackpanel One, which has some content, an Image, and a defualt hidden SubStackpanel. When clickin the Image, the image should rotate 90 degrees, and slide down the SubStackpanel.
When clicking the Image again, the Image should rotate back to its original position, and the SubStackpanel should slide up to the default hidden position.
I almost got this working, the problem is that I dont know how to use the same Trigger event, on two different Storyboard animations. So right now only the first animation on the button and the SubStackpanel occurs, everytime the Image is clicked.
I´ve tried the AutoReverse property, but it fires immediately after the animation is done. This should of course only be happening when the user clicks the Image the second time.
I would like to achieve this, only using markup.
This is my currently code:
<Grid>
<StackPanel Grid.Row="0" Orientation="Vertical" Background="Beige" >
<StackPanel.Triggers>
<EventTrigger SourceName="ImageShowPanelTwo" RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SubPanel" Storyboard.TargetProperty="(StackPanel.Height)" From="0" To="66" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger SourceName="ImageShowPanelTwo" RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SubPanel" Storyboard.TargetProperty="(StackPanel.Height)" From="66" To="0" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</StackPanel.Triggers>
<TextBlock>Panel One</TextBlock>
<Image Name="ImageShowPanelTwo" Width="26" Height="26" Source="ImageRotate.png" RenderTransformOrigin=".5,.5" >
<Image.RenderTransform>
<RotateTransform x:Name="AnimatedRotateTransform" Angle="0" />
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="0"
To="90"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="90"
To="0"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
<StackPanel Name="SubPanel" Background="LightGreen" Height="66">
<TextBlock>SubPanel</TextBlock>
<TextBlock>SubPanel</TextBlock>
</StackPanel>
</StackPanel>
</Grid>
Hope you can help :)
Blend for Visual Studio can be used to do it in a better, simpler way, without dealing with a lot of code.
Here is the list of steps of doing it.
Step 1: Open the project in Blend for Visual Studio and in Visual Studio simultaneously.
Step 2: In Blend, create a new storyboard around all the elements that you wish to animate with it.
Let's call it "Storyboard1".
Step 3: Now, open the storyboard that we just created and click on the small arrow just beside the "+" and click on "Duplicate" in the drop down menu. Then, a new storyboard called "Storyboard1_Copy" will be created.
Step 4: Rename this new storyboard to something that you like, say, "Storyboard1_Rev".
Step 5: You must have guessed it by now. Select the duplicated storyboard and from the drop down menu, click on "Reverse".
Step 6: Now you have two storyboards ready: one for animating some elements as you like and the other for reversing that sequence of animation. Just like you call a storyboard from the C# code, you can call the reversing storyboard from the same, subject to some conditions which check if the elements are already animated or not. For this, I use a bool variable, whose value is changed each time some animation occurs on a set of elements(that is, false if the elements are not already animated and true if they are).
Illustration with an example:
I'll create an application with a simple layout. It has a button, an image and a rectangular area on the screen.
The idea is that, whenever you click on the button once, the image should be maximized and should be minimized back to original size when the button is clicked twice and so on. That is, the reverse animation should happen every other time the button is clicked. Here are some screenshots showing how it happens:
You can see that the current state of the image is shown in the button. It shows "Zoom In" when the image is in its initial small size and "Zoom Out" when it is maximized.
And finally, here is the C# code for handling the clicks of the button:
bool flag = false;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (!flag)
{
Button.Content = "Zoom Out";
Storyboard1.Begin();
flag = true;
}
else
{
Button.Content = "Zoom In";
Storyboard1_Rev.Begin();
flag = false;
}
}
All you have to do is have a status flag that shows the current status of the element(s) that you wish to animate and animate it(them) in forward or reverse timeline as per the value of the flag.
Instead of trying to set the Animation using that event, use a bool property to bind to instead:
<Image Name="ImageShowPanelTwo" Width="26" Height="26" Source="ImageRotate.png"
RenderTransformOrigin=".5,.5" >
<Image.RenderTransform>
<RotateTransform x:Name="AnimatedRotateTransform" Angle="0" />
</Image.RenderTransform>
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRotated}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="0"
To="90"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsRotated}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="90"
To="0"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
I trust that you can define your own bool property and invert it upon each MouseDown event occurrence to complete this functionality. As it is set to true the first Animation will start and as it is set to false the second will start.
This is how I solved my problem:
Created four storyboards for the Stackpanel and the arrow:
<Storyboard x:Key="RotateIconUp">
<DoubleAnimation Storyboard.TargetName="IconExpand" Storyboard.TargetProperty="(TextBlock.RenderTransform).(RotateTransform.Angle)" From="0" To="90" Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="RotateIconDown">
<DoubleAnimation Storyboard.TargetName="IconExpand" Storyboard.TargetProperty="(TextBlock.RenderTransform).(RotateTransform.Angle)" From="90" To="0" Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="SlideGridDown">
<DoubleAnimation Storyboard.TargetName="GridDetails" Storyboard.TargetProperty="(Grid.Height)" From="0" To="180" Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="SlideGridUp">
<DoubleAnimation Storyboard.TargetName="GridDetails" Storyboard.TargetProperty="(Grid.Height)" From="180" To="0" Duration="0:0:0.4" />
</Storyboard>
Then I trigger the storyboards from codebehind when the arrow is clicked:
private void ExpandDetails() {
try {
if (!pm_IsExanded) {
Storyboard Storyboard = (Storyboard)FindResource("RotateIconUp");
Storyboard.Begin(this);
Storyboard = (Storyboard)FindResource("SlideGridDown");
Storyboard.Begin(this);
pm_IsExanded = true;
BorderMain.BorderBrush = pm_BrushConverter.ConvertFromString("#000000") as Brush;
} else {
Storyboard Storyboard = (Storyboard)FindResource("RotateIconDown");
Storyboard.Begin(this);
Storyboard = (Storyboard)FindResource("SlideGridUp");
Storyboard.Begin(this);
pm_IsExanded = false;
BorderMain.BorderBrush = pm_BrushConverter.ConvertFromString("#d0d0d0") as Brush;
}
} catch (Exception ee) {
GlobalResource.WriteToLog("Error in ExpandDetails", ee);
}
}

Why isn't my windows phone silverlight rotation animation working?

I've got this in my XAML:
<Grid.Resources>
<Storyboard x:Name="Storyboard_Animation">
<DoubleAnimation
Storyboard.TargetName="button_Submit"
Storyboard.TargetProperty="Angle"
From="0"
To="360"
Duration="0:0:1"></DoubleAnimation>
</Storyboard>
</Grid.Resources>
I have the button in the same Grid:
<Button Grid.Row="0" Grid.Column="1" Content="Submit" Margin="0" Name="button_Submit" Click="button_Submit_Click">
<Button.Template>
<ControlTemplate>
<Image Source="Images/buttonImage.png"></Image>
</ControlTemplate>
</Button.Template>
<Button.RenderTransform>
<RotateTransform></RotateTransform>
</Button.RenderTransform>
</Button>
I have this in my click method:
private void button_Submit_Click(object sender, RoutedEventArgs e)
{
Storyboard_Animation.Begin();
}
When I click on my button I get the error:
Cannot resolve TargetProperty Angle on specified object.
But, I have no idea what I'm supposed to use other than Angle.
I have this other piece of code that works fine:
private void RotateStar()
{
button_Submit.RenderTransformOrigin = new Point(0.5, 0.5);
button_Submit.RenderTransform = new RotateTransform();
DoubleAnimation da = new DoubleAnimation
{
From = 0,
To = 360,
Duration = TimeSpan.FromSeconds(0.3)
};
Storyboard.SetTarget(da, button_Submit.RenderTransform);
Storyboard.SetTargetProperty(da, new PropertyPath(RotateTransform.AngleProperty));
Storyboard sb = new Storyboard();
sb.Children.Add(da);
sb.Begin();
}
I'd like to put the storyboard in the XAML instead of in code. What do I need to add/change in my XAML version so that it works like the code version?
Try this:
<Grid.Resources>
<Storyboard x:Name="Storyboard_Animation">
<DoubleAnimation
Storyboard.TargetName="button_Submit"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
From="0"
To="360"
Duration="0:0:1">
</DoubleAnimation>
</Storyboard>
</Grid.Resources>
Your problem is in incorrect using "TargetProperty". Button doesn't have Angle property, you should use it for RenderTransform.
Such this:
<Storyboard x:Name="Storyboard_Animation">
<DoubleAnimation Duration="0:0:1" To="-180.221" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="button" d:IsOptimized="True"/>
</Storyboard>
Regards,
Roman.

Change the content of label in StoryBoard

I have a label in Code below:
<Window.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard FillBehavior="Stop" >
<DoubleAnimation RepeatBehavior="Forever"
Storyboard.TargetName="Transform"
Storyboard.TargetProperty="X"
From="220" To="-1300" Duration="0:0:15" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<StackPanel >
<Label Content="Hello! your Welcome" HorizontalAlignment="Right" FontSize="11">
<Label.RenderTransform>
<TranslateTransform x:Name="Transform" X="0" Y="0"/>
</Label.RenderTransform>
</Label>
</StackPanel>
the label moves into my window but I want to Change content
of label when the priod is started again.
if you suggest a code with List<> insted of label will be better.
You can run the animation once, then on the completed event change the content of the label, and then continue to run the animation.
Your code will be more compact, if you move the animation to the resources:
XAML:
<Window.Resources>
<DoubleAnimation x:Key="da"
Completed="DoubleAnimation_Completed"
From="220" To="-1300" Duration="0:0:15"
/>
</Window.Resources>
<StackPanel>
<Label x:Name="lbl" Content="Hello! your Welcome" HorizontalAlignment="Right" FontSize="11">
<Label.RenderTransform>
<TranslateTransform x:Name="Transform" X="0" Y="0"/>
</Label.RenderTransform>
</Label>
</StackPanel>
Code Behind:
private void DoubleAnimation_Completed( object sender, EventArgs e ) {
this.lbl.Content = "Second time";
DoubleAnimation da = this.Resources[ "da" ] as DoubleAnimation;
TranslateTransform tr = this.Transform;
da.Completed -= DoubleAnimation_Completed;
da.RepeatBehavior = RepeatBehavior.Forever;
tr.BeginAnimation( TranslateTransform.XProperty, da );
}
private void Window_Loaded( object sender, RoutedEventArgs e ) {
DoubleAnimation da = this.Resources[ "da" ] as DoubleAnimation;
TranslateTransform tr = this.Transform;
tr.BeginAnimation( TranslateTransform.XProperty, da );
}

Resources