You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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中,未关联到可视化树的控件不会执行完整的布局和渲染逻辑,尤其是第三方图表控件通常依赖可视化树上下文完成绘制。

具体修复步骤

  1. 临时将控件加入可视化树触发渲染
    修改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;
    }
    
  2. 移除硬编码宽高,适配打印页面
    原代码中给ContentPresenter设置了固定的800x600宽高,可能导致图表与打印页面尺寸不匹配。改为直接使用PageSize的宽高,让图表自适应打印区域。

  3. 优化绑定(可选)
    显式设置ContentPresenter的DataContext,避免潜在的绑定上下文问题:

    contentPresenter.DataContext = _chart;
    
  4. 复用界面已有图表(可选)
    原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 08:13:10