在WPF中将XAML文档转换为PDF文件导出
编写文档模板页面
1、新建Page页面,将顶部节点更改为FlowDocument
,后台代码不需要,可直接删掉
2、实现一个表格页面
直接上代码,自己看,其中需要注意的是,如果非静态页面(即内容是需要绑定的),只需要给它一个DataContext
上下文即可,后文会有讲到
<FlowDocument
x:Class="wpf_xaml2pdf_demo.Resources.StudentTemplate"
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:local="clr-namespace:wpf_xaml2pdf_demo.Resources"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<FlowDocument.Resources>
<Style x:Key="BorderedTable" TargetType="Table">
<Setter Property="CellSpacing" Value="0" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#000" />
</Style>
<Style x:Key="BorderedCell" TargetType="TableCell">
<Setter Property="BorderThickness" Value="0.5" />
<Setter Property="BorderBrush" Value="#000" />
<Setter Property="Padding" Value="10" />
</Style>
</FlowDocument.Resources>
<Table FontSize="25" Style="{StaticResource BorderedTable}">
<Table.Columns>
<TableColumn Width="784" />
<TableColumn Width="300" />
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="2" FontSize="40">
<Paragraph Margin="30" TextAlignment="Center">
学生成绩单
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="2">
<Table
Margin="20,20,20,0"
FontSize="25"
Style="{StaticResource BorderedTable}">
<Table.Columns>
<TableColumn Width="200" />
<TableColumn />
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="2" Style="{StaticResource BorderedCell}">
<Paragraph FontSize="25" TextAlignment="Center">
学生成绩信息
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph TextAlignment="Right">
姓名
</Paragraph>
</TableCell>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph>
<Run Text="{Binding Name}" />
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph TextAlignment="Right">
班级
</Paragraph>
</TableCell>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph>
<Run Text="{Binding Class}" />
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph TextAlignment="Right">
语文成绩
</Paragraph>
</TableCell>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph>
<Run Text="{Binding Chinese}" />
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph TextAlignment="Right">
数学成绩
</Paragraph>
</TableCell>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph>
<Run Text="{Binding Math}" />
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph TextAlignment="Right">
英语成绩
</Paragraph>
</TableCell>
<TableCell Style="{StaticResource BorderedCell}">
<Paragraph>
<Run Text="{Binding English}" />
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="2">
<Table
Margin="20,0,20,20"
FontSize="25"
Style="{StaticResource BorderedTable}">
<Table.Columns>
<TableColumn />
</Table.Columns>
<TableRowGroup>
<TableRow>
<TableCell ColumnSpan="2" Style="{StaticResource BorderedCell}">
<Paragraph FontSize="25" TextAlignment="Left">
班主任评语
</Paragraph>
</TableCell>
</TableRow>
<TableRow>
<TableCell ColumnSpan="2" Style="{StaticResource BorderedCell}">
<Paragraph TextAlignment="Center">
<Run Text="{Binding Comments}" />
</Paragraph>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</TableCell>
</TableRow>
</TableRowGroup>
</Table>
</FlowDocument>
后台逻辑
1、导出按钮命令
public MainWindowViewModel()
{
ExportCommand = new DelegateCommand(ExportPdfMethod);
}
private delegate void DoExportPdfMethod();
public DelegateCommand ExportCommand { get; set; }
//线程同步
private void ExportPdfMethod()
{
Application.Current.Dispatcher.BeginInvoke(
new DoExportPdfMethod(() => SavePDF()),
DispatcherPriority.ApplicationIdle
);
}
2、加载并填充模板数据
private FlowDocument FillFlowDocument()
{
FlowDocument doc = (FlowDocument)Application.LoadComponent(new Uri("/wpf_xaml2pdf_demo;component/Resources/StudentTemplate.xaml", UriKind.RelativeOrAbsolute));
doc.DataContext = new Models.Student
{
Name = "傲慢与偏见",
Class = "三年一班",
Chinese = 99,
Math = 59,
English = 66,
Comments = "此乃难得一见的奇才,未来可期!!!(Tips:这文字是绑定的,不是静态数据)"
};
return doc;
}
Tips:这里使用Application.LoadComponent
加载模板文件,并显示转换为FlowDocument
,上文所说的可以删除后台文件,就是因为可以直接对该文档设置上下文,给它一个模型实体,模板xaml那边正常使用Binding即可
3、弹窗并转换文档为pdf
private void SavePDF()
{
try
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "(*.pdf)|*.pdf";
saveFileDialog.FileName = DateTime.Now.ToString("yyyyMMddHHmmssfff");
//填充模板
if (studentTemplate == null)
{
studentTemplate = FillFlowDocument();
}
if (saveFileDialog.ShowDialog() == true)
{
string xpsPath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), $"Xps_{DateTime.Now:yyyyMMddHHmmssfff}.xps");
using (XpsDocument xpsDocument = new XpsDocument(xpsPath, FileAccess.Write))
{
XpsDocumentWriter documentwriter = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
documentwriter.Write(((IDocumentPaginatorSource)studentTemplate).DocumentPaginator);
}
PdfSharp.Xps.XpsConverter.Convert(xpsPath, saveFileDialog.FileName, 0);
DeletedInvalidFile(xpsPath);
MessageBox.Show($"PDF文件保存成功,路径:{saveFileDialog.FileName}");
}
}
catch (Exception ex)
{
MessageBox.Show($"保存PDF时发生异常:{ex}");
}
}
Tips:这里主要分为3步,先弹出一个文件保存对话框让用户选择,再将模板文件写入到一个临时目录xps中间文件,最后掉了个库将文档转换为pdf保存即可。