Reputation: 2711
If you try the following XAML code, you'll notice some strange behavior.
<Canvas Width="300" Height="300">
<Rectangle Canvas.Left="50" Canvas.Top="50" Width="100" Height="100"
Stroke="Blue" StrokeThickness="1"/>
<Canvas.RenderTransform>
<ScaleTransform CenterX="50" CenterY="50" ScaleX="2" ScaleY="2"/>
</Canvas.RenderTransform>
</Canvas>
The upper left corner of the blue rectangle is located at 50, 50 on the canvas. Similarly, the center of the ScaleTransform is specified at 50, 50. However, you'll note the resulting scaled canvas does not have the upper left corner of the rectangle in the center as I would expect. My question is, why not? And if this is the expected behavior of the ScaleTransform, what's the point?
UPDATE
Here is what I believe ScaleTransform is doing:
Tx is the translation value, Cx is the original center, and Sx is the scaling factor. As you can see, the result should translate the rectangular "selection area" to match the viewport. Except it doesn't.
Upvotes: 4
Views: 2007
Reputation: 2711
For anyone looking to solve the same or similar problem, these fine folks figured it out:
Smooth animation using MatrixTransform?
It's not trivial and I believe the ScaleTransform is implemented somewhat incorrectly, making this the only clean approach.
Upvotes: 0
Reputation: 61379
I just tried this XAML, and it indeed worked as I would expect ScaleTransform to work.
Setting The "Center" property of a scale transform doesn't say: "Put this spot in the center of my control". It just says "Scale as if this was the center". It is easier to see in Rotate Transform (which uses a similar concept).
If you set up the same canvas with a RotateTransform, with the Center set to (0, 0), the whole canvas rotates around that point. If you set it to (50, 50), the canvas rotates around the upper left corner of the rectangle, etc.
This doesn't move the rectangle to the center of the canvas either, it is just the point to apply the transformation "from". So in scale transform, if my center is (0, 0), then all the scaling happens to the bottom and right. Put it at (50, 50) and it becomes a little bigger at the top and left, but the majority is still at the bottom and right. Put it at (150, 150) and all directions expand equally.
Update
I'm not sure about the reflected implementation, but here is another way to think about it. ScaleTransform is designed to simply scale a control. Scaling should not involve moving child elements relative to each other (that would be translation), this motion would be necessary to get the behavior you describe. The "center" variables are just the center of the transformation, they do not affect the position of an element relative to the parent (especially in a canvas, where these values are hard-coded.)
Also, all the transforms are "render" transforms, which means it just affects the display, the underlying control remains the same. No scaling you could ever do should make an object that is in the upper left corner of a parent object suddenly appear in the center.
Update 2 I believe I see what that final check is doing :).
To do a "centered" scale transform, you need to adjust your coordinate space. Scale operations in matrices (IIRC) are always applied from "0,0". According to MSDN, the "offset" property:
The OffsetX property is so named because it specifies the amount to translate the coordinate space along the x-axis.
This obviously won't translate any controls, it is just adjusting the coordinate space for the transform.
Update 3 One more try...
I agree that changing the center of the scaling results in a non-uniform scale, and I could even imagine a scenario where that upper left corner appears to be in the middle of the scaled canvas. To do so, I would try putting the center in the other corner (at 250,250). This is going to be a lot of trial and error to find the exact point and scale factor that you need.
That being said, the question asked why the posted code didn't result in this. I believe that if you think about what "scaling from a center" actually results in, it will be obvious that any scale from Quadrant II is not going to result in a point from Quadrant 2 being moved closer to the origin, it will always move further away (from what I discussed above).
Just to clarify, I am putting the "origin" at the center of the canvas.
Hopefully that makes sense. Please let me know if I can clarify anything!
Upvotes: 1