使用PrintDocument打印LiveCharts2图表时DocumentPaginator页面空白问题排查
问题:LiveCharts2图表通过DocumentPaginator打印时内容为空
我用LiveCharts2制作了多个图表,需要两种打印方式:单独打印(已用PrintDialog.PrintVisual实现,正常工作),以及和其他测量数据合并成一个文档打印(打算通过PDF打印机转成PDF)。目前图表显示正常,PrintVisual打印也没问题,但用DocumentPaginator打印时页面内容是空的,请问哪里操作错了?
ViewModel代码
using LiveChartsCore; using LiveChartsCore.SkiaSharpView; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace TestGraphPrintApp { class ViewModel { private ICommand _printCommand; public ISeries[] Series { get; set; } = new ISeries[] { new LineSeries<double> { Values = new double[] { 2, 1, 3, 5, 3, 4, 6 }, Fill = null } }; public ICommand PrintCommand => _printCommand ?? (_printCommand = new RelayCommand<Visual>((param) => { var dialog = new PrintDialog(); bool? result = dialog.ShowDialog(); if (result.HasValue && result.Value) { ChartPaginator paginator = new ChartPaginator(this, new System.Windows.Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight)); dialog.PrintDocument(paginator, "test"); } }, obj => true)); } }
XAML代码
<Window x:Class="TestGraphPrintApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF" xmlns:local="clr-namespace:TestGraphPrintApp" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:ViewModel/> </Window.DataContext> <Window.Resources> <DataTemplate x:Key="PrintSampleChartDataTemplate" DataType="{x:Type local:ViewModel}"> <lvc:CartesianChart Series="{Binding Series}" AnimationsSpeed="0" Width="800" Height="600"/> </DataTemplate> </Window.Resources> <StackPanel> <lvc:CartesianChart Name="Chart" Width="800" Height="380" AnimationsSpeed="0" Series="{Binding Series}"> </lvc:CartesianChart> <Button Content="Print" Width="Auto" HorizontalAlignment="Right" Command="{Binding PrintCommand}" CommandParameter="{Binding ElementName=Chart}"/> </StackPanel> </Window>
ChartPaginator代码
using LiveChartsCore.SkiaSharpView.WPF; using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; namespace TestGraphPrintApp { class ChartPaginator : DocumentPaginator { private ViewModel _chart; public ChartPaginator(ViewModel chart, Size pageSize) { _chart = chart; PageSize = pageSize; } public override bool IsPageCountValid => true; public override int PageCount => 1; public override Size PageSize { get; set; } public override IDocumentPaginatorSource Source => null; public override DocumentPage GetPage(int pageNumber) { if (!(App.Current.MainWindow.Resources["PrintSampleChartDataTemplate"] is DataTemplate template)) { throw new Exception("Could not find a DataTemplate for printing."); } var contentPresenter = new ContentPresenter { Content = _chart, ContentTemplate = template, Width = 800, Height = 600 }; contentPresenter.Measure(this.PageSize); contentPresenter.Arrange(new Rect(0, 0, this.PageSize.Width, this.PageSize.Height)); contentPresenter.UpdateLayout(); return new DocumentPage(contentPresenter, this.PageSize, new Rect(), new Rect()); } } }
问题原因及修复方案
核心问题
ChartPaginator中创建的ContentPresenter未加入可视化树,导致LiveCharts2图表控件没有触发完整的渲染流程,最终打印内容为空。WPF中,未关联到可视化树的控件不会执行完整的布局和渲染逻辑,尤其是第三方图表控件通常依赖可视化树上下文完成绘制。
具体修复步骤
临时将控件加入可视化树触发渲染
修改GetPage方法,创建一个隐藏的临时窗口承载ContentPresenter,确保图表完成渲染后再生成打印页面:public override DocumentPage GetPage(int pageNumber) { if (!(App.Current.MainWindow.Resources["PrintSampleChartDataTemplate"] is DataTemplate template)) { throw new Exception("找不到打印用的DataTemplate。"); } var contentPresenter = new ContentPresenter { Content = _chart, ContentTemplate = template, Width = PageSize.Width, Height = PageSize.Height }; // 创建隐藏窗口临时承载控件,触发渲染 var tempWindow = new Window { Visibility = Visibility.Hidden, WindowStyle = WindowStyle.None, ShowInTaskbar = false }; tempWindow.Content = contentPresenter; tempWindow.Show(); // 强制布局更新 contentPresenter.Measure(PageSize); contentPresenter.Arrange(new Rect(0, 0, PageSize.Width, PageSize.Height)); contentPresenter.UpdateLayout(); // 生成打印页面 var documentPage = new DocumentPage(contentPresenter, PageSize, new Rect(), new Rect()); // 清理临时窗口 tempWindow.Close(); return documentPage; }移除硬编码宽高,适配打印页面
原代码中给ContentPresenter设置了固定的800x600宽高,可能导致图表与打印页面尺寸不匹配。改为直接使用PageSize的宽高,让图表自适应打印区域。优化绑定(可选)
显式设置ContentPresenter的DataContext,避免潜在的绑定上下文问题:contentPresenter.DataContext = _chart;复用界面已有图表(可选)
原PrintCommand传递了界面上的Chart控件作为参数,但ChartPaginator并未使用。如果想复用已渲染好的图表,可修改ChartPaginator直接接收Visual对象:// 修改ChartPaginator类 class ChartPaginator : DocumentPaginator { private Visual _chartVisual; public Size PageSize { get; set; } public ChartPaginator(Visual chartVisual, Size pageSize) { _chartVisual = chartVisual; PageSize = pageSize; } public override bool IsPageCountValid => true; public override int PageCount => 1; public override IDocumentPaginatorSource Source => null; public override DocumentPage GetPage(int pageNumber) { _chartVisual.Measure(PageSize); _chartVisual.Arrange(new Rect(0, 0, PageSize.Width, PageSize.Height)); _chartVisual.UpdateLayout(); return new DocumentPage(_chartVisual, PageSize, new Rect(), new Rect()); } } // 修改ViewModel中的PrintCommand public ICommand PrintCommand => _printCommand ?? (_printCommand = new RelayCommand<Visual>((param) => { var dialog = new PrintDialog(); bool? result = dialog.ShowDialog(); if (result.HasValue && result.Value) { ChartPaginator paginator = new ChartPaginator(param, new System.Windows.Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight)); dialog.PrintDocument(paginator, "test"); } }, obj => true));
内容的提问来源于stack exchange,提问作者user20943029
相关产品推荐
相关产品推荐

