19

I consider this a pretty simple request, but I can't seem to find a conclusive answer in my searches. How can I determine the bounds of a particular visual element in my window, relative to some other parent element?

I've tried using LayoutInformation.GetLayoutSlot but this just seems to return a Rect at 0,0 and doesn't reflect the actual location of the element.

What I'm trying to do is take a "screenshot" of a window using RenderTargetBitmap and then crop it to a particular element, but I can't get the element's bounds to know what to crop the bitmap to!

devios1
  • 36,899
  • 45
  • 162
  • 260

4 Answers4

21

It is quite simple:

public static Rect BoundsRelativeTo(this FrameworkElement element,
                                         Visual relativeTo)
{
  return
    element.TransformToVisual(relativeTo)
           .TransformBounds(LayoutInformation.GetLayoutSlot(element));
}

In fact it may be overkill to put it in a separate method.

Ray Burns
  • 62,163
  • 12
  • 140
  • 141
  • 8
    `GetLayoutSlot` gets the space that's allocated in the layout for the element, but the actual element size could be different if it has an explicit width/height and/or a transform. To get the "true" size rect, try `element.RenderTransform.TransformBounds(new Rect(element.RenderSize))`. – nmclean Aug 16 '13 at 13:45
  • This didn't work for me, see Mauro Sampletro's or DanW's answer below which does work. – Michael Brown May 28 '20 at 01:31
9

The LayoutSlot option didn't work for me at all. This ended up giving me a child position relative to a specified parent/ancestor control:

    public static Rect BoundsRelativeTo(this FrameworkElement child, Visual parent)
    {
        GeneralTransform gt = child.TransformToAncestor(parent);
        return gt.TransformBounds(new Rect(0, 0, child.ActualWidth, child.ActualHeight));
    }
DanW
  • 1,976
  • 18
  • 14
  • 1
    This worked for me, the accepted answer did not. Working with a Border in a Grid with WPF in .NET Framework 4.5.2. – pauldendulk Jan 31 '18 at 08:03
5

Taking into account a few suggestions i found here this solved the problem for me.

item.TransformToVisual( relativeToElement )
    .TransformBounds( new Rect( item.RenderSize ) );
Mauro Sampietro
  • 2,739
  • 1
  • 24
  • 50
1

Nevermind, I finally managed to figure it out using a combination of LayoutInformation.GetLayoutSlot() (although I probably could have used either ActualWidth/ActualHeight or RenderSize) and UIElement.TranslatePoint().

Seems a rather complicated solution when it could be as simple as this:

myElement.GetBounds( relativeElement );

Oh well. Maybe time for an extension method. :)

devios1
  • 36,899
  • 45
  • 162
  • 260
  • 1
    I was saying there should be. – devios1 Jan 07 '14 at 00:39
  • 1
    Would you please show the complete solution? I didn't get it to work. It was always wrong relative to some parent element. For now, I'm converting everything to screen coordinates with `myElement.PointToScreen(new Point())` which is okay for handling WM_NCHITTEST. But I still consider it a hack. – ygoe Jan 11 '14 at 14:20
  • We all are happy that you solved your problem. Please provide us your solution here. – Nasenbaer Jun 11 '19 at 09:25
  • @Nasenbaer Sorry I haven't done .NET development in some time. I suggest reading the documentation for `TranslatePoint`. – devios1 Jun 11 '19 at 18:48