TranslatePoint within a Canvas

2019-08-17 06:46发布

问题:

I have a scroll viewer in my application that contains a canvas, in which I have a tree custom-drawn tree structure. I'm trying to get the position of a particular node element in the canvas relative to the scroll viewer (so I can scroll to it), but my attempts aren't working.

I've tried using marker.TranslatePoint(new Point(0, 0), scrollViewer) (where marker is the element in the canvas), but this is just returning the position of the canvas, rather than the marker. Similarly, if I try marker.TranslatePoint(new Point(0, 0), layoutCanvas), I invariably just get (0,0) as the result, regardless of where the marker actually is.

Here's my code:

var marker = m_Metadata[node].Marker;
var location = marker.TranslatePoint(new Point(0, 0), scrollViewer); // This inorrectly gives the position of the canvas, rather than the marker.
var size = new Size(marker.Width, marker.Height);
var markerArea = new Rect(location, size);

double horizontalOffset = (markerArea.Right + markerArea.Left - scrollViewer.ViewportWidth) / 2;
double verticalOffset = (markerArea.Bottom + markerArea.Top - scrollViewer.ViewportHeight) / 2;

I've also tried using marker.TransformToVisual(scrollViewer).Transform(new Point(0, 0), but this gives the same results.

I can work around it by using Canvas.GetLeft, Canvas.GetTop et al, but this is messy and convoluted (since they won't always be left- and top-aligned).

How can I fix this, or does it just not work for canvases?

回答1:

Have you tried using VisualTreeHelper.GetOffset(Visual obj)? I'm not in front of Studio, but I seem to recall using that for just this sort of thing in the past...



回答2:

I've written a simple workaround method for this problem. It works, but it's not very clean, so if anyone has an answer to this I'd still appreciate it! Here's the code I'm currently using:

private static Point GetCanvasChildPosition(FrameworkElement element)
{
    var canvas = element.Parent as Canvas;

    double left = Canvas.GetLeft(element);
    double top = Canvas.GetTop(element);

    bool isLeftAligned = !double.IsNaN(left);
    bool isTopAligned = !double.IsNaN(top);

    double x;
    double y;

    if (isLeftAligned)
    {
        x = left;
    }
    else
    {
        x = canvas.Width - Canvas.GetRight(element) - element.Width;
    }

    if (isTopAligned)
    {
        y = top;
    }
    else
    {
        y = canvas.Height - Canvas.GetBottom(element) - element.Height;
    }

    return new Point(x, y);
}