I'm having trouble with getting the actual size (bounding box) of Shapes.
I tried to use both RenderSize and ActualSize but they return values that don't make sense. However, using these methods for UIElements works great.
if you can help me with this I will be greateful.
You can get the Bounding Box for any Visual
using TransformToVisual
So if you have a Polygon
defined like this
<Canvas Name="canvas">
<Polygon Name="polygon" Canvas.Left="12" Canvas.Top="12"
Points="0,75 100,0 100,150 0,75"
Stroke="Purple"
Fill="#9999ff"
StrokeThickness="1"/>
</Canvas>
Then you can add a Border
around its Bounding Box with the following code
private void AddBorderForFrameworkElement(FrameworkElement element)
{
Rect bounds = element.TransformToVisual(canvas).TransformBounds(new Rect(element.RenderSize));
Border boundingBox = new Border { BorderBrush = Brushes.Red, BorderThickness = new Thickness(1) };
Canvas.SetLeft(boundingBox, bounds.Left);
Canvas.SetTop(boundingBox, bounds.Top);
boundingBox.Width = bounds.Width;
boundingBox.Height = bounds.Height;
canvas.Children.Add(boundingBox);
}
However, you may not always get the desired results using this since the Bounding Box will not always be the Bounds for what is actually drawn. If you instead define your Polygon
like below where you start to draw where x=100 then the Bounding Box will be much larger then what is drawn
<Polygon Name="polygon" Canvas.Left="140" Canvas.Top="12"
Points="100,75 200,0 200,150 100,75"
Stroke="Purple"
Fill="#9999ff"
StrokeThickness="1"/>
Bounding Box comparison
I've run into this problem too and found that a good way to get the exact bounding box for shapes, one that includes the stroke too if there's any, and works for virtually any path I've thrown at it, is the VisualContentBounds
property from the WPF Visual class.
The problem with this is that it's internal (found it with Reflector), so you can only use it for built-in WPF shapes (since you can't override it outside the assembly) and you need to get it through reflection:
Rect visualContentBounds = (Rect)GetPrivatePropertyValue(myShape, "VisualContentBounds");
/*...*/
private static object GetPrivatePropertyValue(object obj, string propName)
{
if (obj == null)
throw new ArgumentNullException("obj");
Type t = obj.GetType();
PropertyInfo pi = t.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (pi == null)
throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
return pi.GetValue(obj, null);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With