In WPF, how can I get the display size of a control before it actually displays?

I am doing an individual rendering in a subclass of Decorator. Our rendering requires the creation of complex geometries that only re-create when the actual size is changed. Thus, I moved the creation of the geometry to my own function called UpdateGeometry , which creates and then freezes the geometry for use in OnRender . This new function should only be called in response to a change in ActualWidth or ActualHeight .

Even better, it looks like we should just override OnRenderSizeChanged , which, according to the documentation, ...

"When overridden in a derived class, the system participates in the rendering operations that are directed by the layout. This method is called after the layout and before rendering if the RenderSize element has been changed as a result of updating the layout."

However, regardless of whether I use overriding or listening to notifications about changes in the ActualWidth and ActualHeight , my log shows OnRender how this happens first! Um ... Wha ??

To be sure that this is not what I did in my code, I created a subclass of the bare-bones decorative decoder and added a log there, both at the input and at the output of the overrides. Here is the whole class ...

 using System; using System.Windows.Controls; public class TestControl : Decorator { protected override void OnRender(System.Windows.Media.DrawingContext drawingContext) { Console.WriteLine("OnRender Entered"); base.OnRender(drawingContext); Console.WriteLine("OnRender Exited"); } protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo) { Console.WriteLine("OnRenderSizeChanged Entered"); base.OnRenderSizeChanged(sizeInfo); Console.WriteLine("OnRenderSizeChanged Exited"); } } 

And how I was afraid ... here is the conclusion ...

 OnRender Entered OnRender Exited OnRenderSizeChanged Entered OnRenderSizeChanged Exited 

So what am I missing here?

More importantly, how can I get the ActualWidth and ActualHeight after the layout subsystem has completed its task, but before the control has been processed, so I can create the geometry before I need it to override OnRender ?

My latest implementation overrides ArrangeOverride since the value that was passed contains a size containing the values ​​of ActualWidth and ActualHeight after the main layout system takes into account HorizontalAlignment and VerticalAlignment with the values ​​of "Stretch", minima and maxima, etc., but what they really depend on the value returned from this override, so it’s a bit more complicated than this is.

In any case, I'm still wondering why the OnRenderSizeChanged call OnRenderSizeChanged not occur when it should. Thoughts?

Mark

+6
source share
1 answer

In general, you should be able to get the correct ArrangeOverride size. This does not include things like Margin, but this probably should not be taken into account. You can either use the size passed as a parameter, as your "render" size, or use the return value of base.ArrangeOverride.

EDIT:

The OnRender method is called from the Arrange method after calling OnArrangeOverride. OnRenderSizeChanged, on the other hand, is called from UpdateLayout, which is effectively dispatched to simultaneously execute for the given section of the visual tree. This is why OnRenderSizeChanged is called after OnRender.

The documentation may refer to "rendering" as if it was actually displayed on the screen, rather than by calling OnRender. WPF can cache rendering commands for this element and execute them if necessary. Thus, the fact that OnRender is called before OnRenderSizeChanged does not mean that the actual rendering commands will be displayed on the screen at this time.

You can change your OnRenderSizeChanged to force OnRender to be called again using:

 protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo) { Console.WriteLine("OnRenderSizeChanged Entered"); base.OnRenderSizeChanged(sizeInfo); this.InvalidateVisual(); Console.WriteLine("OnRenderSizeChanged Exited"); } 

You can also skip your OnRender code if RenderSize is "0.0".

+4
source

Source: https://habr.com/ru/post/885838/


All Articles