I have a small button that should adjust vertically and horizontally. I Would like to use Storyboard and manipulate the X and Y under transform.
And I would like to do it code-behind.
The button moves to the correct position, but no animation is active.
private void AnimatePlayerMovement(Player player)
{
//This will hold hour animation
Piece.RenderTransform = new CompositeTransform();
//New storyboard
Storyboard storyboard = new Storyboard();
//New DoubleAnimation - Y
DoubleAnimation translateYAnimation = new DoubleAnimation();
translateYAnimation.From = this.Path[player.from, 1];
translateYAnimation.To = this.Path[player.to, 1];
translateYAnimation.EasingFunction = new ExponentialEase();
translateYAnimation.EasingFunction.EasingMode = EasingMode.EaseOut;
translateYAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
Storyboard.SetTarget(translateYAnimation, Piece);
Storyboard.SetTargetProperty(translateYAnimation,
"(UIElement.RenderTransform).(CompositeTransform.TranslateY)");
storyboard.Children.Add(translateYAnimation);
//New DoubleAnimation - X
DoubleAnimation translateXAnimation = new DoubleAnimation();
translateXAnimation.From = this.Path[player.from, 0];
translateXAnimation.To = this.Path[player.to, 0];
translateXAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
Storyboard.SetTarget(translateXAnimation, Piece);
Storyboard.SetTargetProperty(translateXAnimation,
"(UIElement.RenderTransform).(CompositeTransform.TranslateX)");
storyboard.Children.Add(translateXAnimation);
storyboard.Begin();
}
And the button in xaml
<Button x:Name="Piece" Height="50" Width="50" HorizontalAlignment="Left"
Margin="115,400,0,0" VerticalAlignment="Top" Click="Button_Click"
RenderTransformOrigin="0.5,0.5">
<Button.Template>
<ControlTemplate>
<Image Source="Assets/piece.png"/>
</ControlTemplate>
</Button.Template>
</Button>
I have tested your code and the animation works properly. You can find the working repo on GitHub. As the code is almost 1:1 copy of your sample, except I hardcoded the From and To property values of the animations. Thus I think the problem you are seeing is that this.Path[player.from, 0] and this.Path[player.to, 0] values are the same (or very similar). This way the button jumps to the this.Path[player.from, 0] location and stays there, not moving further.
Related
I want to move a FrameworkElement, e.g. a TextBlock, across a Canvas from left to right whenever a button is pressed and held. If you just click the button, the FrameworkElement should be moved 1 pixel.
This is possible to achieve with the code below but I get a lot of stuttering while the FrameworkElement is moving.
The XAML part:
<Canvas>
<TextBlock x:Name="MoveTextBlock" Text="Move Me" Canvas.Left="0"/>
<RepeatButton Content="Move" Width="90" Height="30" Canvas.Bottom="20"
Canvas.Left="20" Click="RepeatButton_Click" Delay="150" Interval="2"/>
</Canvas>
In code-behind:
private void RepeatButton_Click(object sender, RoutedEventArgs e)
{
Canvas.SetLeft(MoveTextBlock, Canvas.GetLeft(MoveTextBlock) + 1);
}
What I have tried (but not necessarily in the right way):
Using CacheMode
Adjusting Delay and Interval for the RepeatButton
Using a BackgroundWorker
Using a Storyboard
The Storyboard almost did the job but I then got another problem with the animation slowing down after a while, which is not what I want either.
Is it possible to completely avoid stutter?
EDIT:
I gave the Storyboard another attempt. I solved the problem I had with the animation slowing down (all animations got added to the same Storyboard), but now the stuttering happens in this solution too:
private void RepeatButton_Click(object sender, RoutedEventArgs e)
{
DoubleAnimation doubleAnimation = new DoubleAnimation();
double left = Canvas.GetLeft(MoveTextBlock);
doubleAnimation.From = left;
doubleAnimation.To = left + 1;
doubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(0));
Storyboard.SetTargetName(doubleAnimation, MoveTextBlock.Name);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(Canvas.LeftProperty));
Storyboard moveTextBlockStoryboard = new Storyboard();
moveTextBlockStoryboard.Children.Add(doubleAnimation);
moveTextBlockStoryboard.Begin(MoveTextBlock);
}
To learn about animation and UI, I'm making a basic WPF/C# application where a user selects the number of vehicles to display then those vehicles (ie images of different vehicles) appear in the canvas and move around.
The WPF is very simple:
<Grid>
<Canvas x:Name="MenuTabCanvas" Visibility="Visible">
<Label x:Name="AnimateDemo" Content="Animate!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="104" Background="#25A0DA" Foreground="White" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Cursor="Hand" MouseDown="AnimateGrid" Canvas.Left="640" Canvas.Top="87"/>
<Canvas x:Name="AnimationCanvas" Canvas.Top="150" Canvas.Left="224" Width="814" Height="489">
</Canvas>
</Grid>
I started with a fade animation using the method described in this post and it works fine. Then I tried the translatetransform as shown below leaving the fade code in comments, and the images appear but nothing moves:
private void AnimateGrid(object sender, EventArgs e)
{
int NumberOfVehicles = 5;
var sb = new Storyboard();
for (int i = 0; i < NumberOfVehicles; i++)
{
//create & add the images to our target canvas
Image Img = getRandomVehicleImage(); //returns image of vehicle
AnimationCanvas.Children.Add(Img);
Canvas.SetTop(Img, 30 + 60 * i); //position image w/in canvas
Canvas.SetLeft(Img, 30 + 80 * i);
//add an animation
DoubleAnimation myAnimation = new DoubleAnimation()
{
// From = 0,
To = 150,
Duration = TimeSpan.FromSeconds(2),
};
Storyboard.SetTarget(myAnimation, Img);
// Storyboard.SetTargetProperty(myAnimation, new PropertyPath(Button.OpacityProperty));
Storyboard.SetTargetProperty(myAnimation, new PropertyPath(TranslateTransform.XProperty));
sb.Children.Add(myAnimation);
}
sb.Begin();
}
I have been able to get it to work with TranslateTransform.BeginAnimation but I would prefer to use the storyboard here.
Why does the translate transform behave differently than the opacity animation and what do I need to do to get it to function as intended?
By default, there is no TranslateTransform applied to a UIElement. So if you want to move an Image, you first have to set its RenderTransform property to a TranslateTransform, and then set the TargetProperty to the correct property path:
Img.RenderTransform = new TranslateTransform();
...
Storyboard.SetTargetProperty(myAnimation, new PropertyPath("RenderTransform.X"));
Alternatively, you could directly animate the TranslateTransform, even without a Storyboard:
var transform = new TranslateTransform();
Img.RenderTransform = transform;
transform.BeginAnimation(TranslateTransform.XProperty, myAnimation);
I want to rotate a polygon made in XAML with C# code, however I'm stuck on the Propertypath. Does someone know what I should use instead?
This is the C# code I have right now:
public void Rotate()
{
Storyboard rotate = new Storyboard();
DoubleAnimation myDoubleAnimation = new DoubleAnimation();
myDoubleAnimation.From = 0;
myDoubleAnimation.To = 360;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath("(Polygon.RenderTransform).(RotateTransform.Angle)"));
Storyboard.SetTargetName(myDoubleAnimation, Arrowhead.Name);
rotate.Children.Add(myDoubleAnimation);
rotate.Begin(Arrowhead);
}
And here is the polygon(triangle) I want to rotate in XAML:
<Polygon Fill="#41b1ff"
Stroke="Gray"
StrokeThickness="2"
Points="80,60,100,40,100,40,120,60"
Grid.ColumnSpan="3"
Grid.RowSpan="3"
Name="Arrowhead"
/>
Your code seems to work fine. You need to add the transform you're trying to modify though:
<Polygon
Fill="#41b1ff"
Stroke="Gray"
StrokeThickness="2"
Points="80,60,100,40,100,40,120,60"
Name="Arrowhead">
<Polygon.RenderTransform>
<RotateTransform/>
</Polygon.RenderTransform>
</Polygon>
Can anyone explain to me what I am doing wrong here? I am most certainly a beginner at C# and I do not want to leave it up to XAML when it comes to animating this image on the screen.
_sb = new Storyboard();
DoubleAnimation moveXAnim = new DoubleAnimation();
moveXAnim.Duration = TimeSpan.FromMilliseconds(5000);
moveXAnim.From = 0;
moveXAnim.To = 300;
_sb.Children.Add(moveXAnim);
Storyboard.SetTarget(moveXAnim, Person);
Storyboard.SetTargetProperty(moveXAnim, "(Canvas.Left)");
_sb.Begin();
All the examples I find are XAML.
What makes you think it does not work? I assume that Person is a UIElement.
Is your Person element contained inside a Canvas? The example below should work for your code>
<Canvas>
<TextBlock
Text="Hi"
x:Name="Person" />
</Canvas>
I have 2 buttons created in code behind ,I am trying to draw a line that connects them by getting the button coordinates, but it doesn't work the way that I wanted , I am new to this , am I doing this the right way?
I searched internet for line connecting 2 controls, but I just want a simple one that make use of coordinates to connect them .
Here are my codes :
Button btn1 = new Button();
btn1.Content = "Hello";
btn1.Width = 150;
btn1.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
wrapPanel1.Children.Add(btn1);
btn1.PreviewMouseDown += new MouseButtonEventHandler(btn1_MouseDown);
Button btn2 = new Button();
btn2.Content = "World";
btn2.Width = 150;
btn2.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
btn2.PreviewMouseDown += new MouseButtonEventHandler(btn1_MouseDown);
wrapPanel1.Children.Add(btn2);
private void ShowLocation(ContentControl element)
{
var location = element.PointToScreen(new Point(0, 0));
MessageBox.Show(string.Format(
"{2}'s location is ({0}, {1})",
location.X,
location.Y,
element.Content));
Line redLine = new Line();
redLine.X1 = location.X;
redLine.Y1 = location.Y;
redLine.X2 = 323;
redLine.Y2 = 167;
//Create a red Brush
SolidColorBrush redBrush = new SolidColorBrush();
redBrush.Color = Colors.Red;
//Set Line's width and color
redLine.StrokeThickness = 4;
redLine.Stroke = redBrush;
// Add line to the Grid.
wrapPanel1.Children.Add(redLine);
}
private void btn1_MouseDown(object sender, RoutedEventArgs e)
{
var element = sender as ContentControl;
if (element != null)
{
ShowLocation(element);
}
}
As you notice the X2 and Y2 coordinates I just random giving it a number but the X1 and Y1 is suppose to be drawn from the button but it is not.
The line is appearing somewhere else away from the button, but the coords I use are the coords of the button.
Also, I have to dynamically create many buttons from db, This is just testing out yet I am stuck here.
__EDIT____
trying out with 1 button , i realise when maximize and minimize , the coords are different , this is how it looks like , the button seems to increase its height everytime i click on it to generate the line .
i want the line to start from the end of the button width at the side , if its not possible , it will be good for the button to overlap the line but is that possible?
The main problem is that WPF mostly uses layout-based positioning (Grid, DockPanel, etc), instead of Windows Forms, which is coordinate-based. This means, that real location of left top element's corner depends from layout control being used and its current settings (and yes, this usually blows up your mind, if you are very new to WPF).
If you want to manage position of elements by coordinates in WPF, then you should use Canvas (you can easily translate this sample from XAML to C#):
<Canvas>
<Button Canvas.Left="10" Canvas.Top="10" Width="20" Height="20" Content="A"/>
<Button Canvas.Left="50" Canvas.Top="50" Width="20" Height="20" Content="B"/>
<Line Canvas.Left="30" Canvas.Top="30" X2="20" Y2="20" StrokeThickness="4" Stroke="Red"/>
</Canvas>