Visual brush using control which isn't rendered?

1.1k views Asked by At

I'm playing around with an idea at the moment and I've hit a brick wall. I'm using a console app to create a visual control (DevExpress chartcontrol to be precise) in memory, I'm then trying to save that control to an image using a VisualBrush but it won't work because (I assume) the control isn't drawn to the screen.

I've put my code in below so you know where I am at the moment. Does anyone know how I could possibly save this control to an image (ideally jpg, but anything will do...) using a console app? I really don't want to have to render it to the screen even for a millisecond just to be able to save it...

static void sl_CreateDetail(FrameworkElement chartControl1, CreateAreaEventArgs e)
{
        var brush = new VisualBrush(chartControl1);
        var visual = new DrawingVisual();
        DrawingContext context = visual.RenderOpen();

        context.DrawRectangle(brush, null,
            new Rect(0, 0, chartControl1.ActualWidth, chartControl1.ActualHeight));
        context.Close();

        var bmp = new RenderTargetBitmap((int)chartControl1.ActualWidth,
            (int)chartControl1.ActualHeight, 96, 96, PixelFormats.Pbgra32);

        bmp.Render(visual);
        e.Data = bmp;
}
2

There are 2 answers

1
Clemens On

Before rendering the control you would have to manually do its layout by calling Measure and Arrange. This requires that you specify the desired size of the control, e.g. by explicitly setting its Width and Height properties.

There is no need for VisualBrush and DrawingVisual, you can directly render the control to the RenderTargetBitmap.

chartControl1.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
chartControl1.Arrange(new Rect(0, 0, chartControl1.Width, chartControl1.Height));
chartControl1.UpdateLayout();

var bmp = new RenderTargetBitmap((int)chartControl1.ActualWidth,
    (int)chartControl1.ActualHeight, 96, 96, PixelFormats.Pbgra32);

bmp.Render(chartControl1);

If the control calculates a preferred size during layout (in Measure), you could perhaps use its DesiredSize property for rendering.

chartControl1.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
chartControl1.Arrange(new Rect(new Point(), chartControl1.DesiredSize));
chartControl1.UpdateLayout();

Note also that the rendering thread's ApartmentState must be STA. In a console application you could simply apply the STAThread attribute to the Main method.

[STAThread]
static void Main(string[] args)
{
    ...
}
0
Hoverfrog On

I tried Measure(), Arrange(), etc, then discovered that these DO work if the Visual has a parent! In my case I was removing the Visual from one container, updating its properties (colour, etc), then trying to use it as a VisualBrush and it wasn't getting updated. Leaving it in the original container for the duration of Measure() and Arrange() fixed it (even though it was all done offscreen).