How can you "plug into" the WPF rendercycle to get accurate results from VisualTreeHelper?

1.1k views Asked by At

I am currently writing a WPF User control (PARENT) which can contain multiple child (CHILD) user controls. I am connecting the (CHILD) controls with polylines.

To do this I need the locations of the CHILD user controls. However, the locations i get from VisualTreeHelper.GetOffset are zero. WPF is probably not finished yet with sizing and placing the CHILD controls in memory, because when I put my code in the OnLoaded event handler of my control I do get correct locations for my child controls.

This is a problem because even after I loaded my PARENT control I still want to be able to add CHILD controls and update my lines.

How I have currently solved this is by overriding the OnRender of my CHILD controls and raising an event for my MAIN control so it knows it can use the VisualTreeHelper to obtain correct values.

This however means that I will need to redraw my lines untill the last CHILD control has finished rendering.

My current solution feels more like a workaround than a solution. How can you "plug into" the WPF rendercycle to get accurate results from VisualTreeHelper?

1

There are 1 answers

0
Nicholas Armstrong On BEST ANSWER

Try overriding ArrangeOverride or OnRender on the parent control. WPF does a three-stage layout/render pass: first, it asks the controls how much space they need (measure), then it tells the controls how much space they actually have given all of the requests received (arrange), and then it actually draws everything inside the regions each control was given (render). For this to work, it follows the visual tree - the root element (say, Window) is told to measure; it has to ask its children to measure, who have to ask their children, etc. all the way down to the leaf elements before the whole thing starts returning all the way back to the root. Then it starts the arrange pass, and finally the render pass.

By watching the children's OnRender, you're implicitly saying that you want to start drawing after measure and arrange have occurred, but before the parent starts drawing itself. This can be made equivalent to the parent's OnRender - which wraps the children's OnRenders. You might also be able to do this in the parent's ArrangeOverride, which wraps the children's arrange pass, which is where (IIRC) the values VisualTreeHelper.GetOffset() accesses actually get set.

Finally, by looking at the parent control, you're implicitly waiting for all the child controls to finish arranging/rendering - which means that you won't have to monkey around trying to figure out when the last child has finished rendering.