Description
openedon Jul 4, 2024
Background and motivation
Any code using the Stretch
(and StretchDirection
) property has to figure out how to scale the content respecting these properties, and how to undo the scaling when mapping coordinates back to the content. From built-in controls, this includes Image
, MediaElement
, Viewbox
and DocumentPageView
which all call a helper method to calculate the scaling.
It would be beneficial to other developers to be able to reuse the code for consistent results including corner cases (such as infinities and near-zero values).
API Proposal
namespace System.Windows.Controls;
public class Viewbox
{
- internal static Size ComputeScaleFactor(Size availableSize, Size contentSize, Stretch stretch, StretchDirection stretchDirection);
+ public static Size ComputeScaleFactor(Size availableSize, Size contentSize, Stretch stretch, StretchDirection stretchDirection);
}
API Usage
void Image_MouseLeftButtonDown(MouseButtonEventArgs e)
{
Point point = e.GetPosition(this);
Size stretchScale = ComputeScaleFactor(RenderSize, new Size(Source.Width, Source.Height), Stretch, StretchDirection);
Point pixelPoint = new Point(point.X / stretchScale.Width, point.Y / stretchScale.Height); // click in image source coordinates
...
}
Alternative Designs
The final scaling transform could be made available as a ScaleTransform
instead. This would provide more robust solution with invertability and built-in ability to transform points and bounds, but with higher computational and memory costs. This could either be a new constructor, such as
public ScaleTransform(Size availableSize, Size contentSize, Stretch stretch, StretchDirection stretchDirection)
or a static method such as
public static ScaleTransform FromStretch(Size availableSize, Size contentSize, Stretch stretch, StretchDirection stretchDirection)
The Viewbox
itself creates a ScaleTransform
with the calculated values and uses it as a visual transform on the child.
Yet more alternatively, there could just be a TranslatePoint
method somewhere (like UIElement
or Viewbox
), but that would have to calculate the scaling each time, which isn't great for usage in mouse move etc.
Risks
No existing API surface is changed or removed, so there shouldn't be breaking changes. The code to calculate the scaling already exists as an internal method.