WPF中FlowDocument打印预览时LiveCharts2内容不显示的解决方法
解决WPF FlowDocument中LiveCharts2图表在打印预览不显示的问题
在WPF项目中,将LiveCharts2的CartesianChart放入FlowDocument的BlockUIContainer中时,打印预览里图表内容无法显示,以下是问题场景的相关代码:
问题代码
1. FlowDocument1.xaml
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF" xmlns:local="clr-namespace:Wpf.Start.Assets.Prints" ColumnWidth="400" FontSize="14"> <Paragraph TextAlignment="Center" FontSize="16" FontWeight="Bold"> <Run Text="{Binding Name}"></Run> </Paragraph> <BlockUIContainer> <Grid Background="#888"> <lvc:CartesianChart Height="300" Series="{Binding Series1}" XAxes="{Binding XAxes1}" YAxes="{Binding YAxes1}" /> </Grid> </BlockUIContainer> </FlowDocument>
2. MainViewModel.cs
var printPre = new PrintPreView("Assets/Prints/FlowDocument1.xaml", DeviceInfo); printPre.ShowDialog();
3. PrintPreView.xaml
<Window x:Class="Wpf.Start.Views.PrintPreView" 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:Wpf.Start.Views" mc:Ignorable="d" Title="" Height="450" Width="800"> <Grid> <DocumentViewer Name="viewer" /> </Grid> </Window>
4. PrintPreView.xaml.cs
public PrintPreView(string fileName, DeviceInfo data) { InitializeComponent(); var flowDocument = (FlowDocument)Application.LoadComponent(new Uri(fileName, UriKind.RelativeOrAbsolute)); flowDocument.DataContext = data; Dispatcher.BeginInvoke(() => { MemoryStream ms = new MemoryStream(); Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); Uri DocumentUri = new Uri("pack://InMemoryDocument.xps"); PackageStore.RemovePackage(DocumentUri); PackageStore.AddPackage(DocumentUri, package); XpsDocument xpsDocument = new XpsDocument(package, CompressionOption.Fast, DocumentUri.AbsoluteUri); XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument); var paginator = (flowDocument as IDocumentPaginatorSource).DocumentPaginator; writer.Write(paginator); viewer.Document = xpsDocument.GetFixedDocumentSequence(); xpsDocument.Close(); }, DispatcherPriority.ApplicationIdle); }
解决方案
问题根源在于:FlowDocument转XPS时,BlockUIContainer中的CartesianChart控件还未完成布局渲染就被写入XPS,导致图表内容无法被捕获。可以通过以下步骤修复:
1. 强制控件完成布局和渲染
在生成XPS前,需要确保FlowDocument中的所有UI控件都完成布局和渲染。可以将FlowDocument临时加载到一个隐藏的FlowDocumentReader中,触发布局更新。
2. 修改PrintPreView.xaml.cs代码
更新构造函数逻辑,先让控件完成渲染再生成XPS:
public PrintPreView(string fileName, DeviceInfo data) { InitializeComponent(); var flowDocument = (FlowDocument)Application.LoadComponent(new Uri(fileName, UriKind.RelativeOrAbsolute)); flowDocument.DataContext = data; // 创建临时FlowDocumentReader触发控件布局 var tempReader = new FlowDocumentReader { Document = flowDocument, Visibility = Visibility.Collapsed, Width = flowDocument.PageWidth, Height = flowDocument.PageHeight }; // 添加到窗口可视化树 (Content as Grid).Children.Add(tempReader); Dispatcher.BeginInvoke(async () => { // 强制更新布局 tempReader.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); tempReader.Arrange(new Rect(tempReader.DesiredSize)); tempReader.UpdateLayout(); // 短暂延迟确保LiveCharts2完成绘制 await Task.Delay(100); MemoryStream ms = new MemoryStream(); Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); Uri DocumentUri = new Uri("pack://InMemoryDocument.xps"); PackageStore.RemovePackage(DocumentUri); PackageStore.AddPackage(DocumentUri, package); XpsDocument xpsDocument = new XpsDocument(package, CompressionOption.Fast, DocumentUri.AbsoluteUri); XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument); var paginator = (flowDocument as IDocumentPaginatorSource).DocumentPaginator; writer.Write(paginator); viewer.Document = xpsDocument.GetFixedDocumentSequence(); xpsDocument.Close(); // 移除临时控件 (Content as Grid).Children.Remove(tempReader); }, DispatcherPriority.Render); }
3. 额外优化:手动触发图表刷新
如果上述方法仍不生效,可在设置DataContext后手动找到CartesianChart并强制刷新:
// 在flowDocument.DataContext = data;之后添加 var blockContainer = flowDocument.Blocks.OfType<BlockUIContainer>().FirstOrDefault(); if (blockContainer?.Child is Grid grid) { var chart = grid.Children.OfType<CartesianChart>().FirstOrDefault(); chart?.InvalidateVisual(); }
内容的提问来源于stack exchange,提问作者omitoufa
相关产品推荐
相关产品推荐

