ContentControl + RenderTargetBitmap + пустое изображение
Я пытаюсь создать несколько диаграмм, не отображая их на экране. Я занимался этим довольно давно и перепробовал много разных вещей, но, похоже, ничего не получалось. Код работает отлично, если я сначала отображаю диаграмму в окне, но если я не отображаю ее в окне, растровое изображение просто белое с черной рамкой (понятия не имею, почему).
Я попытался добавить диаграмму к границе перед рендерингом и присвоить границе зеленый borderBrush. В растровом изображении я вижу зеленый borderBrush, затем черную рамку и белый фон, но без диаграммы. Диаграмма не содержится в черной границе, поэтому я не знаю, откуда это исходит.
Я попытался добавить диаграмму в окно, не вызывая window.Show(), и снова я просто получаю черную границу и белый фон. Однако, если я вызываю window.Show(), растровое изображение содержит диаграмму.
Я попытался использовать DrawingVisual, как описано здесь, тот же результат.
Вот код (не включая добавление элемента к границе или окну):
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;
}
Примечание. Диаграмма представляет собой ContentControl.
Могу ли я в любом случае заставить диаграмму визуализировать, не отображая ее сначала в окне?
3 ответа
Для меня вызов element.Arrange() был отсутствующим элементом.
Если у кого-то есть похожие проблемы с рендерингом элементов RenderTargetBitmap (получение белого / пустого изображения), которые находятся в StackPanel, вы можете временно переместить их в Grid, а затем отрендерить и поместить обратно в 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();