Rotate Object from Code - c#

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>

Related

UWP Storyboard not executing animation correctly

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.

WPF Canvas Fill

I currently have a WPF windows with a Canvas is 600 x 400. Is it possible to scale or automatically zoom in so that the lines take up as much as the 600x600 as possible?
<Border>
<Canvas x:Name="cMap" Width="600" Height="400">
<Line X1="5" Y1="5" X2 ="10" Y2="10" StrokeThickness="2" Stroke="Black"/>
<Line X1="10" Y1="10" X2 ="15" Y2="25" StrokeThickness="2" Stroke="Black"/>
</Canvas>
</Border>
My intention will be to add lines programmatically via code instead of XAML.
Thanks.
Not sure what is your exact usecase, but you could probably benefit by using ViewBox:
<Border>
<Viewbox Stretch="Uniform">
<Canvas x:Name="cMap" Width="15" Height="25">
<Canvas.LayoutTransform>
<ScaleTransform />
</Canvas.LayoutTransform>
<Line X1="5" Y1="5" X2 ="10" Y2="10" StrokeThickness="2" Stroke="Black"/>
<Line X1="10" Y1="10" X2 ="15" Y2="25" StrokeThickness="2" Stroke="Black"/>
</Canvas>
</Viewbox>
</Border>
Hope this helps you!
To draw lines in code you shoud do something like this:
Line line = new Line();
Thickness thickness = new Thickness(101,-11,362,250);
line.Margin = thickness;
line.Visibility = System.Windows.Visibility.Visible;
line.StrokeThickness = 4;
line.Stroke = System.Windows.Media.Brushes.Black;
line.X1 = 10;
line.X2 = 40;
line.Y1 = 70;
line.Y2 = 70;
and don't forget to add:
myCanvas.Children.Add(line);
to put those line in some place
from: Drawing lines in code using C# and WPF
To resize your canvas please read this:
Canvas is the only panel element that has no inherent layout
characteristics. A Canvas has default Height and Width properties of
zero, unless it is the child of an element that automatically sizes
its child elements. Child elements of a Canvas are never resized, they
are just positioned at their designated coordinates. This provides
flexibility for situations in which inherent sizing constraints or
alignment are not needed or wanted. For cases in which you want child
content to be automatically resized and aligned, it is usually best to
use a Grid element.
So as a solution you would make it inside a GRID or using the following code:
public class CanvasAutoSize : Canvas
{
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint)
{
base.MeasureOverride(constraint);
double width = base
.InternalChildren
.OfType<UIElement>()
.Max(i => i.DesiredSize.Width + (double)i.GetValue(Canvas.LeftProperty));
double height = base
.InternalChildren
.OfType<UIElement>()
.Max(i => i.DesiredSize.Height + (double)i.GetValue(Canvas.TopProperty));
return new Size(width, height);
}
}
at your XAML:
<local:CanvasAutoSize VerticalAlignment="Top" HorizontalAlignment="Left"></local:CanvasAutoSize>
from: WPF: How to make canvas auto-resize?

Template doesnt work in Content Control in C#

Here is my xaml
<Canvas x:Name="DesignArea">
<ContentControl
Name="DesignerItem"
Width="100"
Height="100"
Canvas.Top="100"
Canvas.Left="100"
Template="{StaticResource DesignerItemTemplate}">
<Ellipse Fill="Blue" IsHitTestVisible="False"/>
</ContentControl>
<ContentControl Width="130"
MinWidth="50"
Height="130"
MinHeight="50"
Canvas.Top="150"
Canvas.Left="150"
Template="{StaticResource DesignerItemTemplate}">
<Path Fill="Blue"
Data="M 0,5 5,0 10,5 5,10 Z"
Stretch="Fill"
IsHitTestVisible="False"/>
</ContentControl>
</Canvas>
As you can see that the content control use the template just fine with all of it functionality
But I want to do it through C# like this
ContentControl ct = new ContentControl();
ControlTemplate Temp;
Temp = (ControlTemplate)this.FindResource("DesignerItemTemplate");
ct.Template = Temp;
Ellipse ell = new Ellipse();
ell.Fill = new SolidColorBrush(Colors.Black);
ell.Width = 100;
ell.Height = 100;
ell.IsHitTestVisible = false;
ct.Content = ell;
DesignArea.Children.Add(ct);
The Black Ellipse in C# did show up the grid template like the xaml shape
But I can't move, drag drop, resize or rotate Like the content control in the canvas What happen?
Oh I see why
Turn out I need to set the properties of the Canvas too in order to make it work
Canvas.SetLeft(ct, 300);
Canvas.SetTop(ct, 300);
ct.Width = 100;
ct.Height = 100;

How to rotate an image within a StackPanel or Grid in Silverlight

I have an image control sits inside a Grid control. I already have a button to enable zoom-in to this image. After zoom-in, the Horizontal/vertical scroll bars are displayed. And then I rotate the image contained grid, the image and the grid scroll bar are messed up. How should I incorporate both zoom-in and rotate for the image control? The following are the code that I am using in my project.
The image control zoom-in code I used (x is the image control):
if ((x as Image) != null) { x.Height = x.Height * 1.3; x.Width = x.Width * 1.3; }
The rotation code I used (x is the image control):
if ((x as Image) != null)
{
RotateTransform rotate = new RotateTransform(); rotate.Angle = rotateAngle;
rotate.CenterX = x.Width / 2;
rotate.CenterY = x.Height / 2;
x.RenderTransform = rotate;
};
The XAML is:
<ScrollViewer x:Name="scrollViewer" Height="480" Width="615"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<ScrollViewer.Content>
<Grid x:Name="ImageGrid">
<StackPanel x:Name="ImageStackPanel">
<Image Source="..." VerticalAlignment="Center" Width="220" Height="170" ></Image>
</StackPanel>
</Grid>
</ScrollViewer.Content>
</ScrollViewer>
Does anybody have any existing code snippet that I can borrow to resolve this trick?
I think you need to use TransformGroup to use more than one transform at the time:
ScaleTransform myScaleTransform = new ScaleTransform();
myScaleTransform.ScaleY = 3;
RotateTransform myRotateTransform = new RotateTransform();
myRotateTransform.Angle = 45;
// Create a TransformGroup to contain the transforms
// and add the transforms to it.
TransformGroup myTransformGroup = new TransformGroup();
myTransformGroup.Children.Add(myScaleTransform);
myTransformGroup.Children.Add(myRotateTransform);
// Associate the transforms to the image.
x.RenderTransform = myTransformGroup;
This may work for your needs:
<Image x:Name="image" Source="myImageSource" Stretch="Uniform"
HorizontalAlignment="Center" VerticalAlignment="Center"
RenderTransformOrigin="0.5, 0.5">
<Image.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="Rotate"/>
<ScaleTransform x:Name="Scale" />
</TransformGroup>
</Image.RenderTransform>
</Image>
code behind:
Rotate.Angle = 45;
Scale = 0.25;
You may be missing the LayoutTransformer from the Silverlight Toolkit, and the AnimationMediator from one of the Toolkit developers.
With the LayoutTransformer you can set its content to anything, not just images, and apply any transformation with it, and as opposed to the usual RenderTransform, it will affect layout and actual sizes.
I have a similar scenario and I use it like this:
<Grid>
<fs:AnimationMediator x:Name="RotateMediator" LayoutTransformer="{Binding ElementName=LayoutTransformer}" AnimationValue="{Binding Angle, ElementName=RotateTransform, Mode=TwoWay}" />
<fs:AnimationMediator x:Name="ScaleXMediator" LayoutTransformer="{Binding ElementName=LayoutTransformer}" AnimationValue="{Binding ScaleX, ElementName=ScaleTransform, Mode=TwoWay}" />
<fs:AnimationMediator x:Name="ScaleYMediator" LayoutTransformer="{Binding ElementName=LayoutTransformer}" AnimationValue="{Binding ScaleY, ElementName=ScaleTransform, Mode=TwoWay}" />
<tkt:LayoutTransformer x:Name="LayoutTransformer" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<tkt:LayoutTransformer.LayoutTransform>
<TransformGroup>
<RotateTransform x:Name="RotateTransform" />
<ScaleTransform x:Name="ScaleTransform" />
</TransformGroup>
</tkt:LayoutTransformer.LayoutTransform>
<Image x:Name="MyImage" Source="mysource.png" Width="600" Height="800" />
</tkt:LayoutTransformer>
</Grid>
Because of the lack of MultiBinding you'd probably additionally have to manually handle the input value (from Slider controls etc) changed events and then set the AnimationValues of RotateMediator etc accordingly.

Rotate image (control) in Silverlight with Transform

I'm trying to rotate an image in Silverlight and can't seem to get it right. I've tried a few different ways so far and can't find the answer.
<Image Opacity=".5" x:Name="compassImg" Source="compass.png">
<Image.RenderTransform>
<RotateTransform x:Name="compassRotator"></RotateTransform>
</Image.RenderTransform>
</Image>
+
void compass_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
{
Dispatcher.BeginInvoke(() =>
{
compassRotator.Angle = e.SensorReading.TrueHeading;
});
}
and
<Image Opacity=".5" x:Name="compassImg" Source="compass.png"></Image>
+
void compass_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
{
Dispatcher.BeginInvoke(() =>
{
compassImg.RenderTransform = new CompositeTransform()
{
CenterX = 0.5,
CenterY = 0.5,
Rotation = e.SensorReading.TrueHeading
};
//OR (variations with 0.5 and width / 2 for both composite and rotate
compassImg.RenderTransform = new RotateTransform()
{
CenterX = compassImg.Width / 2,
CenterY = compassImg.Height / 2,
Angle = e.SensorReading.TrueHeading
};
});
}
It rotates, but it always rotates around 0/0. What am I doing wrong?
I looked up MSDN, and the second form is correct. http://msdn.microsoft.com/en-us/library/system.windows.media.rotatetransform.centerx.aspx (It is the coordinates, not fraction).
However, if you put a breakpoint where you apply the transform, you may find that Width is NaN. This is because width wasn't set. What you want is the ActualWidth.
One good way for exploration of transforms is to paste the following snippet into your XAML and experiment away.
<StackPanel HorizontalAlignment="Left">
<TextBlock>Center X</TextBlock>
<Slider
Name="RTX" Minimum="0.0" Maximum="116" />
<TextBlock>Center Y</TextBlock>
<Slider
Name="RTY" Minimum="0.0" Maximum="800"/>
<TextBlock>Angle</TextBlock>
<Slider
Name="Angle" Minimum="0.0" Maximum="360" />
</StackPanel>
<Image Source="{Binding ImagePath}" Name="image1">
<Image.RenderTransform>
<RotateTransform Angle="{Binding ElementName=Angle,Path=Value}"
CenterX="{Binding ElementName=RTX, Path=Value}"
CenterY="{Binding ElementName=RTY, Path=Value}"/>
</Image.RenderTransform>
</Image>
You need to set the RenderTransformOrigin Property to "0.5, 0.5", this will rotate the element around its centre.

Categories

Resources