views:

492

answers:

2

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?

A: 

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...

JerKimball
This just gives (0,0) as before, unfortunately.
Will Vousden
Hmm...this may sound like a stupid question, but when is the code you wrote being called? User-initiated event handler? On initialization? Construction? etc? The answer I'm groping for here is maybe you're trying to pull details on a UI bit that hasn't actually finished being composited yet...
JerKimball
Basically I'm trying to get it to scroll to the currently selected node. This will always happen as a result of a user interaction, though, by which point the tree has been correctly rendered.
Will Vousden
A: 

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);
}
Will Vousden