将承载DataVisualization.Charting图表的WindowsFormsHost所在WPF Grid保存为图片
解决方案
问题根源
WPF默认的RenderTargetBitmap仅能捕获纯WPF渲染管线生成的元素内容,WindowsFormsHost底层是独立的Win32子窗口,走GDI渲染逻辑,不属于WPF渲染树的一部分,所以直接导出Grid才会出现尺寸正确但内容全黑的情况。
方案一:保留现有WindowsFormsHost布局,修改导出逻辑
操作步骤如下:
- 第一步:临时调整布局获取完整Grid尺寸
先保存ScrollViewer当前的滚动条可见性设置,将横向、纵向滚动条均设为Hidden,调用ChartGrid.Measure()和ChartGrid.Arrange()方法强制Grid完成完整布局计算,拿到完整Grid的实际宽高。 - 第二步:单独捕获每个图表的位图
遍历Grid中所有的ScrollViewerWindowsFormsHost,取出其内部承载的DataVisualization.Charting.Chart实例,调用Chart自带的SaveImage()方法将图表内容写入内存Bitmap对象,同时通过TransformToAncestor(ChartGrid)方法获取该Host相对于Grid左上角的坐标偏移。 - 第三步:拼接完整图片
新建一张和Grid完整尺寸一致的空位图,通过GDI+的绘图接口将所有图表的内存位图按对应偏移量绘制到空位图上,最后将拼接完成的位图保存到本地即可。 - 第四步:布局复原
导出完成后将ScrollViewer的滚动条可见性恢复为导出前的设置,不影响正常交互。
核心代码示例:
// 1. 计算Grid完整尺寸 var originalHorizonScroll = Scroll.HorizontalScrollBarVisibility; var originalVerticalScroll = Scroll.VerticalScrollBarVisibility; Scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden; Scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; ChartGrid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); ChartGrid.Arrange(new Rect(0, 0, ChartGrid.DesiredSize.Width, ChartGrid.DesiredSize.Height)); // 2. 创建空底图拼接内容 using (var fullBitmap = new Bitmap((int)ChartGrid.ActualWidth, (int)ChartGrid.ActualHeight)) using (var g = Graphics.FromImage(fullBitmap)) { g.Clear(Color.White); // 背景色可按需求调整 // 遍历所有承载图表的Host foreach (var child in ChartGrid.Children.OfType<ScrollViewerWindowsFormsHost>()) { var chart = child.Child as System.Windows.Forms.DataVisualization.Charting.Chart; if (chart == null) continue; // 获取当前图表相对于Grid的坐标偏移 var offset = child.TransformToAncestor(ChartGrid).Transform(new Point(0, 0)); // 把Chart写入内存流再转Bitmap using (var ms = new MemoryStream()) { chart.SaveImage(ms, System.Drawing.Imaging.ImageFormat.Png); ms.Seek(0, SeekOrigin.Begin); using (var chartBmp = new Bitmap(ms)) { g.DrawImage(chartBmp, (float)offset.X, (float)offset.Y); } } } // 保存最终图片 fullBitmap.Save("你的导出路径.png", System.Drawing.Imaging.ImageFormat.Png); } // 3. 复原原有布局状态 Scroll.HorizontalScrollBarVisibility = originalHorizonScroll; Scroll.VerticalScrollBarVisibility = originalVerticalScroll;
方案二:替换为WPF原生图表,彻底规避跨宿主导出问题
如果可以调整技术选型,建议直接替换WindowsFormsHost承载的WinForm图表,改为WPF原生图表控件:
- 可直接使用WPF官方的
System.Windows.Controls.DataVisualization.Toolkit图表库,功能和你当前用的WinForm版DataVisualization.Charting基本对齐,完全适配WPF渲染树,直接使用你之前测试过的ScrollViewer导出方案就能正常导出完整Grid内容,不会出现黑块问题。 - 若需要更丰富的交互和样式,也可以选择开源的OxyPlot、LiveCharts等WPF原生图表库,均支持直接用RenderTargetBitmap导出。
内容的提问来源于stack exchange,提问作者mantra
相关产品推荐
相关产品推荐

