Reputation: 5994
I have a UserControl and that UserControl has to be resized with aspect ratio. That means: width:height = 2:1. Currently I am using this code:
protected override Size ArrangeOverride(Size arrangeBounds)
{
if (ActualWidth == 0 || ActualHeight == 0) return arrangeBounds;
base.ArrangeOverride(arrangeBounds);
double ratio = 2;
if (Parent != null)
{
var size = new Size(arrangeBounds.Height * ratio, arrangeBounds.Height);
double containerWidth = ((FrameworkElement)Parent).ActualWidth;
if (containerWidth < size.Width)
{
double newHeight = arrangeBounds.Height * (containerWidth / size.Width);
canvas.Width = newHeight * ratio;
canvas.Height = newHeight;
}
else
{
canvas.Width = size.Height * ratio;
canvas.Height = size.Height;
}
}
return arrangeBounds;
}
But it is not really working. That means it works but not every time. If I max. the window it sometimes does not get resized, so its a bit "random" if the control gets resized. So if someone would have a better solution if would be very nice.
Upvotes: 2
Views: 5738
Reputation: 2698
The most straightforward solution would be to Bind the Height directly to the Width, through a value converter.
Upvotes: 5
Reputation: 7895
It's a bit late, but I recently came across the same problem and since I did not find a good solution I decided to write my own layout control/decorator and wrote a blog post about it here:
http://coding4life.wordpress.com/2012/10/15/wpf-resize-maintain-aspect-ratio/
Basically my solution was to overwrite both MeasureOverride
and ArrangeOverride
. So far it works very nicely in all of the common containers and I didn't encounter any problems like you described.
I recommend reading the post, where you find a working decorator control, but the most important methods are these:
protected override Size MeasureOverride(Size constraint)
{
if (Child != null)
{
constraint = SizeToRatio(constraint, false);
Child.Measure(constraint);
if(double.IsInfinity(constraint.Width)
|| double.IsInfinity(constraint.Height))
{
return SizeToRatio(Child.DesiredSize, true);
}
return constraint;
}
// we don't have a child, so we don't need any space
return new Size(0, 0);
}
protected override Size ArrangeOverride(Size arrangeSize)
{
if (Child != null)
{
var newSize = SizeToRatio(arrangeSize, false);
double widthDelta = arrangeSize.Width - newSize.Width;
double heightDelta = arrangeSize.Height - newSize.Height;
double top = 0;
double left = 0;
if (!double.IsNaN(widthDelta)
&& !double.IsInfinity(widthDelta))
{
left = widthDelta/2;
}
if (!double.IsNaN(heightDelta)
&& !double.IsInfinity(heightDelta))
{
top = heightDelta/2;
}
var finalRect = new Rect(new Point(left, top), newSize);
Child.Arrange(finalRect);
}
return arrangeSize;
}
public Size SizeToRatio(Size size, bool expand)
{
double ratio = AspectRatio;
double height = size.Width / ratio;
double width = size.Height * ratio;
if (expand)
{
width = Math.Max(width, size.Width);
height = Math.Max(height, size.Height);
}
else
{
width = Math.Min(width, size.Width);
height = Math.Min(height, size.Height);
}
return new Size(width, height);
}
I hope it helps someone!
Upvotes: 4
Reputation: 4157
Wrap your Control with a ViewBox
and set the ViewBox.Stretch
to Uniform
. You can also restrict on MaxWidth and MaxHeight that way.
Upvotes: 4