How can I animate MatrixTransform.Matrix at center? - c#

I am developing a WPF application that allows the user to use multi-touch to manipulate an image using the MatrixTransform.Matrix on RenderTransform. Using this very helpful snippet of code, I was able to animate it with a storyboard created in C#.
The trouble is that currentItem seems to always rotate and scale in relation to the top left hand corner.
How can I make it so it rotates around the center of the FrameworkElement?
Here is what I have so far, a basic example of using the animation:
Matrix fromMatrix = ((MatrixTransform)currentItem.RenderTransform).Matrix;
Matrix toMatrix = new MatrixTransform().Matrix;
//Making sure location of the toMatrix is in the same place as the fromMatrix
toMatrix.OffsetX = fromMatrix.OffsetX;
toMatrix.OffsetY = fromMatrix.OffsetY;
MatrixAnimation myDoubleAnimation = new MatrixAnimation();
myDoubleAnimation.From = fromMatrix;
myDoubleAnimation.To = toMatrix;
myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(.5));
Storyboard myStoryboard = new Storyboard();
myStoryboard.Children.Add(myDoubleAnimation);
Storyboard.SetTarget(myDoubleAnimation, currentItem);
Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath("(FrameworkElement.RenderTransform).(MatrixTransform.Matrix)"));
myStoryboard.Begin(this);
I feel as though I need to add or subtract from the fromMatrix.OffsetY and fromMatrix.OffsetX. I have tried doing this with half the width/height of the currentItem, but this either puts it rotating and scaling around the center (good) OR twice as far away from the center (twice as bad), depending on which way I have the currentItem turned when it begins to animate.

Super late answer here - but I believe you just use the XAML attribute
RenderTransformOrigin="0.5, 0.5"
Place that on your XAML where the Transform is applied. Not really sure you need to do that in code-behind unless you built up that object in code.
Reference: RenderTransformOrigin from MS Docs

Related

How to change orientation of one component in windows phone 8 page with locked orientation

I'm working on Windows Phone 8/8.1 C#/XAML .NET 4.5 Application and I'd like to know how to change orientation of just one control/item on page (rotate it 90 degrees).
I have a webBrowser on my portrait page (that stays locked on that orientation) and the webbrowser needs to be in landscape orientation (and does not rotate).
How can I set the webbrowser to be rotated 90 degrees and stay that way?
So, I've figured one way to do it on my own.
I'm going to put the answer as community wiki so that anyone who comes later can edit and add more options to do this.
The rotation transformation
One of the options is to rotate the element.
This is done by rotation transformation (answer combined from this ans this question).
It can be done in code behind:
//Create a transformation
RotateTransform rt = new RotateTransform();
//and set the rotation angle
rt.Angle = 90; //number of degrees to rotate clockwise
//for counterclockwise rotation use negative number
//default rotation is around top left corner of the control,
//but you sometimes want to rotate around the center of the control
//to do that, you need to set the RenderTransFormOrigin
//of the item you're going to rotate
//I did not test this approach, maybe You're going to need to use actual coordinates
//so this bit is for information purposes only
controlToRotate.RenderTransformOrigin = new Point(0.5,0.5);
//the name of the control is controlToRotate in this instance
controlToRotate.RenderTransform = rt;
Or in XAML:
the browser in this instance is taken from my own code and everything is set so that the item is rotated and takes the full place assigned to it
the browser is in the grid, positioned dynamically, the grid is named so that I can gain access to it simply
the browser needs to have width and height specified, in this case I'm taking it from the width and height of the grid, otherwise it is set automatically somehow and the result is pretty small somehow
The vertical and horizontal alignments are set to center so that the resulting rotation is centered too, otherwise it is not (in dynamic layout)
Code:
<Grid x:Name="ContentPanel">
<phone:WebBrowser x:Name="controlToRotate"
VerticalAlignment="Center"
HorizontalAlignment="Center"
RenderTransformOrigin=".5, .5"
Width="{Binding ElementName=ContentPanel, Path=ActualHeight}"
Height="{Binding ElementName=ContentPanel, Path=ActualWidth}">
<phone:WebBrowser.RenderTransform>
<RotateTransform Angle="90"/>
</phone:WebBrowser.RenderTransform>
</phone:WebBrowser>
</Grid>

Animate a label

I am trying to animate a label in a WPF application. The label gets created programatically (and dynamically) so it is not defined in XAML, but is created in the C# code.
Animation Story
The label appears in the bottom of the window. The label should be positioned lower than the window, so the user can not see it initially. Then a the label moves up (like sliding) and fades out before it reaches the top of the window.
What I have done
I have implemented this behavior myself in an other project. This time I want to use WPF which should perform better.
So far I have seen there should be multiple ways of doing this. Starting with a DoubleAnimation, going by a PathAnimation and VectorAnimation (the last of which I have not tested successfully).
Encountered problems
The animation works nice with a DoubleAnimation, but there is a problem: When I resize the window, the label gets resized too (similar to an anchor in Winforms). When I make the window smaller the label gets smaller too, until it disappears completely. This effect occurs only in the height of the label. I added the code snippet adding the label. Maybe you find some error. Also there should be a better way to implement this (I personally find it very ugly).
Label lbl = new Label()
{
Content = "Test",
FontSize = 36,
Foreground = new SolidColorBrush(Colors.Red),
Background = new SolidColorBrush(Colors.Black),
HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center,
VerticalAlignment = System.Windows.VerticalAlignment.Top
};
lbl.Margin = new Thickness(0, this.MainGrid.ActualHeight + lbl.ActualHeight, 0, 0);
this.MainGrid.Children.Add(lbl);
UpdateLayout();
Transform myTransform = new TranslateTransform();
lbl.RenderTransform = myTransform;
DoubleAnimation AnimationY = new DoubleAnimation((this.MainGrid.ActualHeight + 20) * -1, TimeSpan.FromSeconds(4));
myTransform.BeginAnimation(TranslateTransform.YProperty, AnimationY);
Questions
As I said, I have found multiple ways that seem to achieve the same behavior. Which one could I use to do this. I still have to do the fade-out on the top of the window, but this animation is easier to do compared to the movement.
The animation is fine. The reason your label is resizing is because you are adding it to a Grid. If you want your label to have a fixed height, then set its Height or MinHeight property.

Windows phone - draw graphics

I seem to be unable to figure out how to Draw graphics in a Windows phone app in C#.
I want to Draw e.g. a line. In old school Windows forms i add an event handler to the Windows paint event. And then use a GDI+ Graphics object. But there is no paint event in any controls?
So how do i draw a line on a canvas in a Windows phone app?
I think I need to clarify.
I want to create dynamic graphics and I want to use C#.
I want an update frequency arround 30 fps and I only need a few graphics elements approximately 100.
if you need a line, use the Line class:
<Page xmlns="whatever">
<Grid>
<Line X1="0" Y1="0" X2="10" Y2="10" Stroke="Blue" StrokeThickness="2"/>
</Grid>
</Page>
Other than that, refer to MSDN.
Forget whatever procedural paradigms you might have learned in archaic technologies. Modern technologies are declarative.
You start by adding Canvas to the form and then .Add() graphical objects to the canvas children - it makes the object scaled for you by the engine, which is kind of neat. Usually looks like this:
line = new **Line**();
line.Stroke = Brushes.Yellow;
line.X1 = 0;
line.Y1 = 0;
line.X2 = 100;
line.Y2 = 100;
line.StrokeThickness = 2;
yourCanvas.Children.**Add(line)**;
Just drop the **s from the code - they are for attention grabbing.
Actually, as I drew dynamic hypercubes, I have never used the XAML version, but if you need a static structure or even substructure XAML is the way to go. As I understand, Children.Add() dynamically creates node in the parsed XAML tree, that .NET keeps in memory. If you can not take slight performance hit for dynamicly positioned graphics that WPF imposes, you will have to stick with DirectX or OpenGL for better performance.
If you want low level access to draw 2D or 3D like when using DirectX you can take a look to SharpDX
There are some samples for Windows Phone in Github like:
MiniCube: Display a rotating cube in a DrawingSurfaceBackgroundGrid

Right to left Marquee of text in wpf where width of text block is greater then Window without flickering

I am using following code for animation(right to left marquee):-
private void RightToLeftMarquee(TextBlock tb)
{
doubleAnimation = new DoubleAnimation();
doubleAnimation.From = -tb.Width;
doubleAnimation.To = TickerCanvas.Width;
doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(100));
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(Canvas.Right)"));
sb.Children.Add(doubleAnimation);
sb.Begin(tb,true);
}
This code moves the textblock fine when width of textblock is less then the canvas but when the textblock width is greater then canvas width the marquee flickers.
The flickering you're seeing is probably due to ClearType sub-pixel positioning. You have a few options, but the animation will not look as smooth after applying them:
TextOptions.TextFormattingMode="Display"
This turns on the newer WPF 4.0 ClearType algorithm, which will make the text look crisper.
UseLayoutRounding="True"
Ensures that WPF aligns everything to the device pixels (no more blurry borders, images, etc.)
I always use both of these settings at the root elements of any app (i.e. all Windows) because it generally improves the way the application looks.

RenderTransform without affecting children possibly Inverse

I'm resizing a canvas with touch events as follows:
e.Handled = true;
var transformation = MyCanvas.RenderTransform as MatrixTransform;
var matrix = transformation == null ? Matrix.Identity :transformation.Matrix;
matrix.ScaleAt(e.DeltaManipulation.Scale.X,
e.DeltaManipulation.Scale.Y,
e.ManipulationOrigin.X,
e.ManipulationOrigin.Y);
MyCanvas.RenderTransform = new MatrixTransform(matrix);
The canvas has several child canvasses. I don't want to resize them and in fact need them to go smaller. So looked at RenderTransform.Inverse but am not having any joy.
You can create a custom canvas by inheriting from Panel with
A new dependency property: NonInheritableScale
A binding between bind the transform's scale to the NonInhertiableScale property
overrides of the MeasureOverride() and ArrangeOverride() methods,
so that the take 1.0/NonInhertiableScale.X and 1.0/NonInhertiableScale.Y into account during the layout.
Here is an article on creating custom WPF panels that might help you (a search result, haven't read it).
EDIT after reading the comment below
In that case of a chart you might want to redraw the chart with different axis ranges. A RenderTransform might be not accurate enough and indeed you will have to scale back everything else (axis, labels, gridlines,...)
previous answer, still valid
You will have to iterate through the child canvases and scale them individually. As far as I know there is no build in support for what you want.
You will have to apply both the inverse scale transformation to negate the parent's resize and a scale transformation that will make them smaller.
Post the code you are using to get more detailed help and or feedback.

Categories