ContentControl + RenderTargetBitmap + empty image
Im trying to create some chart images without ever displaying t开发者_开发技巧hose charts on the screen. I'v been at this for quite a while and tried a lot of different things but nothing seems to work. The code works perfectly if I display the chart in a window first, but if I don't display it in a window, the bitmap is just white with a black border (no idea why).
I have tried adding the chart to a border before rendering and giving the border a green borderBrush. In the bitmap, I see the green borderBrush then the black border and white background but no chart. The Chart is not contained in a black boarder so I don't know where that is coming from.
I have tried adding the chart to a window without calling window.Show() and again I just get the black boarder and white background. However if I call window.Show() the bitmap contains the chart.
I have tried using a drawingVisual as explained here, same result.
Here is the code (not including adding the element to a border or window):
private static BitmapSource CreateElementScreenshot(FrameworkElement element, int dpi)
{
if (!element.IsMeasureValid)
{
Size size = new Size(element.Width, element.Height);
element.Measure(size);
element.Arrange(new Rect(size));
}
element.UpdateLayout();
var scale = dpi/96.0;
var renderTargetBitmap = new RenderTargetBitmap
(
(int)(scale * element.RenderSize.Width),(int)(scale * element.RenderSize.Height),dpi,dpi,PixelFormats.Default
);
// this is waiting for dispatcher to perform measure, arrange and render passes
element.Dispatcher.Invoke(((Action)(() => renderTargetBitmap.Render(element))), DispatcherPriority.Render);
return renderTargetBitmap;
}
Note: The chart is a ContentControl.
Is there anyway I can get the chart to render without displaying it in a window first?
Calling element.ApplyTemplate() did the trick.
If someone has similar problems with rendering RenderTargetBitmap (getting white / empty image) items that are in StackPanel you can temporary move them to Grid, then render and put it back in StackPanel
Grid grid = new System.Windows.Controls.Grid() { Background = Brushes.White, Width = iWidth, Height = iHeight };
Panel panel = plot.Parent as Panel;
if (panel != null)
{
panel.Children.Remove(plot);
grid.Children.Add(plot);
grid.Measure(new Size(iWidth, iHeight));
grid.Arrange(new Rect(new Size(iWidth, iHeight)));
}
plot.Measure(new Size(iWidth, iHeight));
plot.Arrange(new Rect(new Size(iWidth, iHeight)));
plot.ApplyTemplate();
plot.UpdateLayout();
grid.ApplyTemplate();
grid.UpdateLayout();
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(
iWidth,
iHeight,
96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(grid);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
MemoryStream memoryStream = new MemoryStream();
encoder.Save(memoryStream);
bitmap = new System.Drawing.Bitmap(memoryStream);
if (panel != null)
{
grid.Children.Remove(plot);
panel.Children.Add(plot);
}
plot.Measure(new Size(iWidthBefore, iHeightBefore));
plot.Arrange(new Rect(new Size(iWidthBefore, iHeightBefore)));
plot.UpdateLayout();
For me, calling element.Arrange() was the missing piece.
精彩评论