0
votes

I am trying to programmatically take a screenshot of a control that I will never actually display on the screen (it is a duplicate of a control is shown in a different area of the application - this area is just writing a report).

I can set the control size to a fixed size using the following code:

Size renderSize = new Size(1000, 1000);
chartControl.Measure(renderSize);
chartControl.Arrange(new Rect(renderSize));
chartControl.UpdateLayout();

This correctly sets the size of the control to 1000x1000, but unfortunately the height of the control can vary - so I either risk losing a part of the picture, or include a region of blank canvas just to make sure.

I've tried various different approaches, but what I really want is something like:

chartControl.Resize("Auto");    // Pseudo code
chartControl.UpdateLayout();

Does anybody know a practical way to do this?

EDIT:

Just to clarify: at present the UserControl "chartControl" is currently never added to any container. I'm happy for that to remain the case, or to create a dummy container (like a Window) if this can "trick" WPF into sizing the UserControl...

EDIT 2:

Thanks to @Lennart for pointing me in the right direction for this:

It seems that DesiredSize is only available (i.e. not (0,0)) after the Measure call has been made, but after the Measure call, the Desired size is the minimum of the control's actual desired size and the size that it has been given in the Measure call. My original effort set the Measure too small, so I never found out the true desired size of the chartControl.

From this, the following ought to work:

Size renderSize = new Size(2000, 2000);
chartControl.Measure(renderSize);
chartControl.Measure(chartControl.DesiredSize);
chartControl.Arrange(new Rect(renderSize));
chartControl.UpdateLayout();

However, the second call to Measure doesn't have any affect - the ActualWidth and height after the first call becomes 2000, but doesn't get updated on the second call to Measure.

The work-around would be to destroy the original chartControl once its DesiredSize has been determined, and then create a new one using the previously determined DesiredSize. It seems a bit clunky, though...

1
Can't you override the MeasureOverride() method of your chart control to calculate its size by yourself? - Lennart
Visibility.Hidden hides the control, but reserves the space it occupies in the layout. so there should not be a problem using an invisible form and have it layouted just like its visible counterpart. - Cee McSharpface
If you want to set the control to the size of the container class you can set the horizontal & vertical alignment to stretch & all margins to 0 - PaulF
Can you check if chartControl.DesiredSize has a correct value after your Measure call, but before the Arrange? - Lennart
DesiredSize is exactly what you are looking for. If a UIElement has something like an "auto" size, you would get it from the DesiredSize property after calling Measure. - Clemens

1 Answers

0
votes

Thanks to @Lennart for pointing me in the right direction for this, and everyone else who gave pointers:

It seems that DesiredSize is only available (i.e. not (0,0)) after the Measure call has been made, but after the Measure call, the Desired size is the minimum of the control's actual desired size and the size that it has been given in the Measure call. My original effort set the Measure too small, so I never found out the true desired size of the chartControl.

This appears to work:

Size overSize = new Size(2000, 2000);    // Something oversized.
chartControl.Measure(overSize);
chartControl.Arrange(new Rect(chartControl.DesiredSize));
chartControl.UpdateLayout();

// Take a screenshot of the chart control
BitmapSource bitmapSource = ScreenshotHelper.CreateScreenshot(chartControl, new Int32Rect(0, 0, (int)chartControl.ActualWidth, (int)chartControl.ActualHeight));