I want to know how to rotate and move the shapes which are drawn on inkcanvas in wpf. I am using VS 2015 and working on a project named WhiteBoard. On that board I am using Inkcanvas, which is used to draw and erase shapes like circles, rectangles etc.
Thanks in advance.
You can rotate or move the entire InkCanvas. Check this:
<Window.Resources>
<Storyboard x:Key="RotateTransformStoryboard">
<DoubleAnimation Storyboard.TargetName="inkCanvas" From="0" To="359" BeginTime="00:00:00" Duration="00:00:05"
RepeatBehavior="1"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)" >
</DoubleAnimation>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard Storyboard="{StaticResource RotateTransformStoryboard}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<InkCanvas Grid.Row="0" x:Name="inkCanvas" RenderTransformOrigin="0.5,0.5">
<InkCanvas.RenderTransform>
<TransformGroup>
<RotateTransform Angle="0" />
</TransformGroup>
</InkCanvas.RenderTransform>
</InkCanvas>
<Button x:Name="btn1" Content="transform" Grid.Row="1" Height="30" />
</Grid>
Related
I would like to visualize multiple circles, each of which has its own animation using a path. Now I have a button that I like to click to start animation for all these circles in the view. I am new to WPF and I would like to stick to MVVM as much as possible. What makes the most sense to me is to create ItemsControl which has Canvas in the view and binding the ItemSource to my viewmodel.
The issue I have is I don't know set up RouteEvent to button click inside the ItemsControl.
<EventTrigger RoutedEvent="Button.Click" SourceName=" PlayButton"> clearly it does not find the button with that name because the MyCircle object does not have the button. See the following for my source code.
my view (XMAL) source code
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button x:Name="PlayButton" Click="Play_Click" Content="Play" Grid.Row="0" Grid.Column="1"/>
<Button x:Name="StopButton" Click="Stop_Click" Content="Stop" Grid.Row="1" Grid.Column="1"/>
</Grid>
<Grid Grid.Row="1">
<Canvas>
<ItemsControl ItemsSource="{Binding MyItemsModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Transparent"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate x:Name="ClockwiseBobbinsDataTemplate">
<Path Fill="Red" x:Name="ClockwiseBobbinsPath">
<Path.Data>
<EllipseGeometry x:Name="MyCircle" RadiusX="5" RadiusY="5"/>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Button.Click" SourceName="PlayButton">
<BeginStoryboard>
<Storyboard>
<PointAnimationUsingPath
Storyboard.TargetName="MyCircle"
Storyboard.TargetProperty="Center"
Duration="0:0:10"
RepeatBehavior="Forever">
<PointAnimationUsingPath.PathGeometry>
<PathGeometry
Figures="{Binding AnimationPath}"
PresentationOptions:Freeze="True" />
</PointAnimationUsingPath.PathGeometry>
</PointAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</Grid>
</Grid>
my viewmodel source code
public class ParentViewModel : BindableBase
{
private List<MyCircle> myItemsModel;
public List<MyCircle> MyItemsModel
{
get { return myItemsModel; }
set
{
SetProperty(ref myItemsModel, value);
}
}
public ParentViewModel()
{
// instantiate MyItemsModel
}
}
MyCircle class
public class MyCircle
{
public double X { get; set; }
public double Y { get; set; }
public PathFigureCollection AnimationPath { get; set; }
public MyCircle(double x, double Y, PathFigureCollection path)
{
// do something
}
}
To go around the issue you should use DataTrigger rather then EventTrigger in ItemsControl.ItemTemplate.
The thing is, that Path.Triggers does accept only EventTrigger so you should move the part with BeginStoryboard to the DataTemplate.Triggers.
Now is the question - which data must trigger the storyboard? You could try to add some property to the viewmodel and set and access it somehow, or add an invisible e.g. CheckBox and act with it.
So remove Path.Triggers and put its content to the DataTemplate.Triggers
<DataTemplate.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding Path="IsChecked" ElementName="ChbPlay"/>
</DataTrigger.Binding>
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="sb1">
<Storyboard>
<SomeAnimation/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="sb1"/>
</DataTrigger.ExitActions>
</DataTrigger>
</DataTemplate.Triggers>
Now you must add an invisible CheckBox and control it with your buttons:
<CheckBox x:Name="ChbPlay" Visibility="Hidden"/>
<Button x:Name="PlayButton" Content="Play" Grid.Row="0" Grid.Column="1">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ChbPlay" Storyboard.TargetProperty="IsChecked">
<BooleanAnimationUsingKeyFrames.KeyFrames>
<DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
</BooleanAnimationUsingKeyFrames.KeyFrames>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
<Button x:Name="StopButton" Content="Stop" Grid.Row="1" Grid.Column="1">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ChbPlay" Storyboard.TargetProperty="IsChecked">
<BooleanAnimationUsingKeyFrames.KeyFrames>
<DiscreteBooleanKeyFrame KeyTime="0" Value="False"/>
</BooleanAnimationUsingKeyFrames.KeyFrames>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
I have a hexagonal Polygon that I am trying to use as an OpacityMask, then have content inside the polygon that can scroll and be clipped at the edges. The problem I encounter is that as the content moves, the OpacityMask moves with it (though by a different amount). Below is my code:
<Window Title="MainWindow" Height="450" Width="800">
<Grid Height="450" Width="800">
<StackPanel>
<Grid ClipToBounds="True">
<Grid.OpacityMask >
<VisualBrush Stretch="None" >
<VisualBrush.Visual>
<Polygon Points="220,225 310,69 490,69 580,225 490, 381 310, 381" Fill="Black" />
</VisualBrush.Visual>
</VisualBrush>
</Grid.OpacityMask>
<Polygon Points="220,225 310,69 490,69 580,225 490, 381 310, 381" Stroke="Black" StrokeThickness="5"/>
<Rectangle x:Name="TestRectangle" Height="400" Width="400" Fill="Red" />
</Grid>
<Button Content="Testing" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="TestRectangle" Storyboard.TargetProperty="Margin"
BeginTime="0:0:0" Duration="0:0:0.5" To="-400,0,0,0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
</Grid>
</Window>
How do I anchor the opacity mask so that the grid content can move with the mask remaining stationary?
Edit: Answer Results and Additional Testing
Using the code in an answer provided, I still get movement of the hexagon:
Begin:
Begin State
End:
End State
However, I have found that by adding a second rectangle that is transparent and that moves in the opposite direction of the red rectangle, I achieve the desired result. While this does work, it seems like there should be a better way to do it.
If you try to set the margin of the rectangle directly, you would notice that it is ignored inside a grid. So one way to solve that would be to put the rectangle inside a border and animate the margin for that border
<Window x:Class="StackverflowTests.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:StackverflowTests"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Height="450" Width="810">
<StackPanel>
<Grid ClipToBounds="True">
<Grid.OpacityMask >
<VisualBrush Stretch="None" >
<VisualBrush.Visual>
<Polygon Points="220,225 310,69 490,69 580,225 490, 381 310, 381" Fill="Black" />
</VisualBrush.Visual>
</VisualBrush>
</Grid.OpacityMask>
<Polygon Points="220,225 310,69 490,69 580,225 490, 381 310, 381" Stroke="Black" StrokeThickness="5"/>
<Border x:Name="TestRectangle">
<Rectangle Height="400" Width="400" Fill="#ff0000"/>
</Border>
</Grid>
<Button Content="Testing" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="TestRectangle" Storyboard.TargetProperty="Margin"
BeginTime="0:0:0" Duration="0:0:0.5" To="-400,0,0,0" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
</Grid>
I am creating fun roulette game where I am trying to rotate eclipse with wheel image inside on its axis (but not 360 degree). Right now, some problem with its rotation, its not rotating as per my requirement. If you will run below code with images attached also. you will get my requirement.
Pls set your screen resolution i.e. Height="1024" Width="768" for understanding my exact requirement. I am also attaching images here. one is background image and another is wheel image.
I am stuck on this from last one week. Any help will be appreciable. Thanks in advance.
Title="MainWindow" Height="1024" Width="768"
WindowStyle="None"
WindowStartupLocation="CenterScreen" WindowState="Maximized">
<Window.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="ball">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="360" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Image/fun_roulette.jpg" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Ellipse Name="ball" Stroke="Black"
RenderTransformOrigin="0.5,0.5" Width="370" Height="200"
Grid.Row="0" Grid.Column="0" Opacity=".4"
Margin="0,30,0,0"
>
<Ellipse.RenderTransform>
<TransformGroup >
<ScaleTransform />
<SkewTransform />
<RotateTransform Angle="45" CenterX="0" CenterY="0" />
<TranslateTransform />
</TransformGroup>
</Ellipse.RenderTransform>
<Ellipse.Fill>
<ImageBrush ImageSource="Image/Roullette_Wheel.jpg" />
</Ellipse.Fill>
<Ellipse.BitmapEffect>
<BevelBitmapEffect BevelWidth="0" />
</Ellipse.BitmapEffect>
<Ellipse.BitmapEffectInput>
<BitmapEffectInput />
</Ellipse.BitmapEffectInput>
</Ellipse>
</Grid>
Download Background Image from here
https://drive.google.com/file/d/0ByTbA6S0c1TaZEo2akgtQjVCbjQ/view?usp=sharing
Download Wheel Image from here
https://drive.google.com/file/d/0ByTbA6S0c1TaY1JzazhudDkzMjA/view?usp=sharing
As I understand you want the ellipse to rotate exactly at the position of the static disc in the background image. Also because of a little 3D effect (perspective effect), rotating the ellipse normally would not be able to produce the desired result. You can try using some 3D feature in WPF but it's some kind of overkill because we still have another choice.
Instead of rotating the whole ellipse, you can just rotate the ImageBrush. I've tried your code and tweaking it a little with some modifications and finally the effect seems to be what you want. Here is the code:
<Window.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames RepeatBehavior="Forever"
Storyboard.TargetProperty="Angle" Storyboard.TargetName="rot">
<EasingDoubleKeyFrame KeyTime="0:0:0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="360" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Image/fun_roulette.jpg" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Ellipse Name="ball" Stroke="Black" RenderTransformOrigin="0.5,0.8"
Grid.Row="0" Grid.Column="0" Opacity=".4"
Margin="6,0,0,0">
<Ellipse.RenderTransform>
<ScaleTransform ScaleX=".195" ScaleY=".45"/>
</Ellipse.RenderTransform>
<Ellipse.Fill>
<ImageBrush ImageSource="Image/Roullette_Wheel.jpg">
<ImageBrush.RelativeTransform>
<TransformGroup >
<RotateTransform CenterX="0.5" CenterY="0.5" x:Name="rot"/>
<SkewTransform/>
<TranslateTransform />
</TransformGroup>
</ImageBrush.RelativeTransform>
</ImageBrush>
</Ellipse.Fill>
<Ellipse.BitmapEffect>
<BevelBitmapEffect BevelWidth="0" />
</Ellipse.BitmapEffect>
<Ellipse.BitmapEffectInput>
<BitmapEffectInput />
</Ellipse.BitmapEffectInput>
</Ellipse>
</Grid>
You should copy and try this exact code, try scanning it for some differences from your original code.
I am trying to have a polygon move from completely off the left of the screen, across the screen, and then completely off the right of the screen, then back again.
I've gotten this working. BUT, for some reason, as soon as the left margin becomes negative, the animation suddenly slows down. As soon as the left margin becomes positive, it speeds up again.
Why does this happen? How can I stop it?
Here's the complete code that demonstrates this:
<Window x:Class="Geometry.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<PathGeometry x:Key="MyGeometry">
<PathGeometry.Figures>
<PathFigure>
<PathFigure.Segments>
<LineSegment Point="0.30,0" />
<LineSegment Point="0.70,1" />
<LineSegment Point="0.40,1" />
<LineSegment Point="0,0" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
<Storyboard x:Key="MovingAnimation">
<ThicknessAnimationUsingKeyFrames RepeatBehavior="1:0:0" FillBehavior="HoldEnd" Storyboard.TargetName="_path" Storyboard.TargetProperty="Margin" >
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="-2.0,0,0,0" />
<LinearThicknessKeyFrame KeyTime="0:0:10" Value="1.0,0,0,0" />
<LinearThicknessKeyFrame KeyTime="0:0:20" Value="-2.0,0,0,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard Storyboard="{StaticResource MovingAnimation}" ></BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Label>Margin:</Label>
<TextBlock Text="{Binding ElementName=_path, Path=Margin.Left, StringFormat={}{0:0.#}}" />
</StackPanel>
<Canvas Name="_canvas" Grid.Row="1">
<Border Margin="0" Width="1" Height="1" VerticalAlignment="Center" HorizontalAlignment="Center">
<Border.RenderTransform>
<ScaleTransform
ScaleX="{Binding ElementName=_canvas, Path=ActualWidth}"
ScaleY="{Binding ElementName=_canvas, Path=ActualHeight}"
CenterX="0"
CenterY="0">
</ScaleTransform>
</Border.RenderTransform>
<Path
Name="_path"
Fill="#CCCCFF"
Data="{StaticResource MyGeometry}"
Width="1.0"
Height="1.0"
>
</Path>
</Border>
</Canvas>
</Grid>
</Window>
I don't have an explanation why the negative margin animates slowly, but I found a workaround.
Instead of animating the Margin of the Path I animated the X value of a TranslateTransform on the Border object that contains the path.
I had to put the TranslateTransform in front of the ScaleTransform so that the translation was applied before the scale. That allows you to use almost the same values in your animation that you used for the Margin.
<Storyboard x:Key="MovingAnimation">
<ThicknessAnimationUsingKeyFrames RepeatBehavior="1:0:0" Storyboard.TargetName="_blank" Storyboard.TargetProperty="Margin" >
<LinearThicknessKeyFrame KeyTime="0:0:0" Value="-1.5,0,0,0" />
<LinearThicknessKeyFrame KeyTime="0:0:10" Value="1,0,0,0" />
<LinearThicknessKeyFrame KeyTime="0:0:20" Value="-1.5,0,0,0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
The ugly part is that I couldn't find a quick way to apply the values in the key frames directly to the X property of the TranslateTransform, so I cheated and used element binding and a placeholder Canvas object.
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="5">
<TextBlock Margin="0,0,5,0" Text="Margin.Left:"/>
<TextBlock Text="{Binding ElementName=_blank, Path=Margin.Left, StringFormat={}{0:0.#}}" />
</StackPanel>
<Canvas Name="_blank" /> <!--Placeholder object-->
<Canvas Name="_canvas" Grid.Row="1">
<Border Margin="0" Width="1" Height="1"
Name="_border"
VerticalAlignment="Center" HorizontalAlignment="Center">
<Border.RenderTransform>
<TransformGroup>
<TranslateTransform X="{Binding Margin.Left, ElementName=_blank}"/>
<ScaleTransform
ScaleX="{Binding ElementName=_canvas, Path=ActualWidth}"
ScaleY="{Binding ElementName=_canvas, Path=ActualHeight}"
CenterX="0"
CenterY="0">
</ScaleTransform>
</TransformGroup>
</Border.RenderTransform>
Even thought the animation is still being applied to a Margin and then to a TranslateTransform through element binding, the delay for a negative margin is gone.
I suspect that the negative margin delay has something to do with the Path being in the Border that was being scaled, but that is conjecture on my part.
If you can find a way to bind the KeyFrame values directly to the X property of the TranslateTransform, that would make this workaround much less ugly.
EDIT:
Figured out the proper binding to use:
<Storyboard x:Key="MovingAnimation2">
<DoubleAnimationUsingKeyFrames RepeatBehavior="1:0:0" Storyboard.TargetName="tt" Storyboard.TargetProperty="X" >
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="-1.5" />
<LinearDoubleKeyFrame KeyTime="0:0:5" Value="1" />
<LinearDoubleKeyFrame KeyTime="0:0:10" Value="-1.5" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
This gets rid of the extra canvas placeholder object.
<Canvas Name="_canvas" Grid.Row="1">
<Border Margin="0" Width="1" Height="1"
Name="_border"
VerticalAlignment="Center" HorizontalAlignment="Center">
<Border.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="tt"/>
<ScaleTransform
ScaleX="{Binding ElementName=_canvas, Path=ActualWidth}"
ScaleY="{Binding ElementName=_canvas, Path=ActualHeight}"
CenterX="0"
CenterY="0">
</ScaleTransform>
</TransformGroup>
</Border.RenderTransform>
Animating Margin property will trigger additional measure/arrange pass which in turn cause a bit more performance impact (though in this example it may not be noticeable). Animation of "render-only" properties on the other hand will not trigger layout re-arrangement and, thus, is more performance friendly.
Please, take a look at a bit easier way to do what, I suppose, you are want to get:
<Window x:Class="Geometry.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="518" Width="530">
<Window.Resources>
<PathGeometry x:Key="MyGeometry">
<PathGeometry.Figures>
<PathFigure>
<PathFigure.Segments>
<LineSegment Point="0.30,0" />
<LineSegment Point="0.70,1" />
<LineSegment Point="0.40,1" />
<LineSegment Point="0,0" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
<Storyboard x:Key="MovingAnimation">
<DoubleAnimationUsingKeyFrames RepeatBehavior="1:0:0" FillBehavior="HoldEnd" Storyboard.TargetName="_scaleTransform" Storyboard.TargetProperty="CenterX" >
<LinearDoubleKeyFrame KeyTime="0:0:0" Value="1.2" />
<LinearDoubleKeyFrame KeyTime="0:0:10" Value="-0.5" />
<LinearDoubleKeyFrame KeyTime="0:0:20" Value="1.2" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard Storyboard="{StaticResource MovingAnimation}" ></BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Label>Margin:</Label>
<TextBlock Text="{Binding ElementName=_scaleTransform, Path=CenterX, StringFormat={}{0:0.#}}" VerticalAlignment="Center" />
</StackPanel>
<!--
<Border Grid.Row="1" Margin="150" BorderBrush="Red" BorderThickness="1">
-->
<Grid Name="_canvas" Grid.Row="1">
<Path Name="_path" Fill="#CCCCFF" Data="{StaticResource MyGeometry}"
Width="1.0"
Height="1.0"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Path.RenderTransform>
<ScaleTransform x:Name="_scaleTransform"
ScaleX="{Binding ElementName=_canvas, Path=ActualWidth}"
ScaleY="{Binding ElementName=_canvas, Path=ActualHeight}"
CenterX="1.2"
CenterY="0.5">
</ScaleTransform>
</Path.RenderTransform>
</Path>
</Grid>
<!--
</Border>
-->
</Grid>
</Window>
From the two answers so far, it's clear that if you want to have a shape fly around the screen, don't animate the margins.
Stewbob solved the problem by animating the X value of a translate transform.
sevenate solved the problem by animating the Center X value of a scale transform.
Another solution is, instead of wrapping the polygon in a border and animating the margin, wrap it up in a canvas and animate the left value.
Wrapping it in a canvas:
<Canvas Name="_canvasFrame" Grid.Row="1">
<Canvas Margin="0" Width="1" Height="1">
<Canvas.RenderTransform>
<ScaleTransform
ScaleX="{Binding ElementName=_canvasFrame, Path=ActualWidth}"
ScaleY="{Binding ElementName=_canvasFrame, Path=ActualHeight}"
CenterX="0"
CenterY="0">
</ScaleTransform>
</Canvas.RenderTransform>
<Path
Name="_path"
Fill="#CCCCFF"
Data="{StaticResource MyGeometry}"
Width="1.0" Height="1.0"
>
</Path>
</Canvas>
</Canvas>
Then animating the left value:
<Storyboard x:Key="MovingAnimation">
<DoubleAnimationUsingKeyFrames
RepeatBehavior="1:0:0"
FillBehavior="HoldEnd"
Storyboard.TargetName="_path"
Storyboard.TargetProperty="(Canvas.Left)" >
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="-1.0" />
<LinearDoubleKeyFrame KeyTime="0:0:10" Value="1.0" />
<LinearDoubleKeyFrame KeyTime="0:0:20" Value="-1.0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
I currently have two buttons that say left and right, and I want them to move a square object left and right respectively.
What its currently doing when i press left is moving the square to the left, and if I press left again, it resets from the center and goes left.
I want it so that when I press left, from where ever it is currently to go left and right.
I know the principle is something like get current objects position and add the canvas coordinates respectively but how do I do this?
<UserControl x:Class="phase_2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<Storyboard x:Name="scroll_me">
<DoubleAnimation x:Name="left_ani" To="0" Duration="0:0:01" Storyboard.TargetName="Rect_Animate" Storyboard.TargetProperty="(Canvas.Left)">
<DoubleAnimation.EasingFunction>
<PowerEase EasingMode="EaseOut"></PowerEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Name="scroll_me2">
<DoubleAnimation x:Name="right_ani" To="200" Duration="0:0:01" Storyboard.TargetName="Rect_Animate" Storyboard.TargetProperty="(Canvas.Left)">
<DoubleAnimation.EasingFunction>
<PowerEase EasingMode="EaseOut"></PowerEase>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="35"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Canvas Grid.Column="1" Grid.Row="1" x:Name="canvas1">
<Rectangle x:Name="Rect_Animate" Width="35" Height="35" Fill="Red" Canvas.Left="80" />
</Canvas>
<Button x:Name="left_btn" Width="35" Height="35" Content="L" Grid.Column="0" Grid.Row="1" Click="left_btn_Click"/>
<Button x:Name="right_btn" Width="35" Height="35" Content="R" Grid.Column="2" Grid.Row="1" Click="right_btn_Click"/>
</Grid>
Only if your object is contained in a Canvas, which in general is not a great layout practice - it isn't flexible.
If you're placing items in a Grid instead, you can do exactly what the designer tools like Blend do: adjust the Margin of any item you want to move. You can have negative margins.