在 A.xaml 界面将 B.xaml 界面导出为 PDF,B.xaml 为 Window 窗体。
调用 windows api 通过打印机导出 PDF。
A.xaml 核心代码:
反射调用 B 界面的方法,获得传入参数后的 B 界面。
private void Export_Click(object sender, RoutedEventArgs e)
{
try
{
thread = new Thread(new ThreadStart(delegate
{
this.Dispatcher.Invoke(DispatcherPriority.Background, (ThreadStart)delegate
{
Assembly assembly = Assembly.GetExecutingAssembly();
var type = assembly.GetType($"namespace");
var assem = assembly.CreateInstance($"namespace", false, BindingFlags.CreateInstance, null, new object[] { "B 界面参数" }, null, null) as Window;
MethodInfo method = assem.GetType().GetMethod("ExportPDF");
Object[] paras = new Object[] { "ExportPDF 方法参数 1", "ExportPDF 方法参数 2" };
method.Invoke(assem, paras);
});
}));
thread.Start();
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
}
B.xaml 核心代码:
将要打印的控件内容重新布局,细节可以自调。可传入多个控件名字,这里取两个。
public void GetPDF(string 参数 1, string 参数 2)
{
// obj1、obj2 分别为要打印的控件名。
// 其它参数随意,这里取导出的 PDF 的名字 (name) 以及路径 (path)
GetPDF(ojb1, obj2, name, path);
}
private void GetPDF(object object1, object object2, string name, string path)
{
PrintDialog pd = new PrintDialog();
var stack = new StackPanel() { };
var stack1 = new StackPanel() { HorizontalAlignment = HorizontalAlignment.Center, Margin = new Thickness(0, 0, 0, 0) };
string childXaml1 = XamlWriter.Save(object2);
StringReader stringReader1 = new StringReader(childXaml1);
XmlReader xmlReader1 = XmlReader.Create(stringReader1);
UIElement clonedChile1 = (UIElement)XamlReader.Load(xmlReader1);
stack.Children.Add(clonedChile);
string childXaml = XamlWriter.Save(object1);
StringReader stringReader = new StringReader(childXaml);
XmlReader xmlReader = XmlReader.Create(stringReader);
UIElement clonedChile = (UIElement)XamlReader.Load(xmlReader);
stack1.Children.Add(clonedChile1);
stack.Children.Add(stack1);
FixedDocumentValuePdf(GetFixedDocumentHorizontal(stack, pd), name, path);
}
若是要打印的内容超过一页,则需要分页。
private FixedDocument GetFixedDocumentHorizontal(FrameworkElement toPrint, PrintDialog printDialog)
{
double sizeWidths = 800;
double sizeHeights = 1045;
Size pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
FixedDocument fixedDoc = new FixedDocument();
toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
toPrint.Arrange(new Rect(new System.Windows.Point(0, 0), toPrint.DesiredSize));
Size size = toPrint.DesiredSize;
double yOffset = 0;
while (yOffset < size.Height)
{
VisualBrush vb = new VisualBrush(toPrint)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Top,
ViewboxUnits = BrushMappingMode.Absolute,
TileMode = TileMode.None,
Viewbox = new Rect(0, yOffset, sizeWidths, sizeHeights)
};
PageContent pageContent = new PageContent();
FixedPage page = new FixedPage();
((IAddChild)pageContent).AddChild(page);
fixedDoc.Pages.Add(pageContent);
page.Width = pageSize.Width;
page.Height = pageSize.Height;
var stack = new StackPanel()
{
Width = sizeWidths,
Height = sizeHeights,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Background = vb,
Margin = new Thickness(0, 0, 0, 0)
};
page.Children.Add(stack);
yOffset += sizeHeights;
}
return fixedDoc;
}
private void FixedDocumentValuePdf(FixedDocument fd, string name, string path)
{
MemoryStream ms = new MemoryStream();
Package package = Package.Open(ms, FileMode.Create);
XpsDocument doc = new XpsDocument(package);
var writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(fd.DocumentPaginator);
doc.Close();
package.Close();
var bytes = ms.ToArray();
ms.Dispose();
string root = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
string dir = root + "Data\\";
if (!System.IO.Directory.Exists(dir))
{
System.IO.Directory.CreateDirectory(dir);
}
var outputFilePath = dir + "\\" + name + ".pdf";
PrintXpsToPdf(bytes, outputFilePath, "pdf", false);
}
打印 PDF:
private void PrintXpsToPdf(byte[] bytes, string outputFilePath, string documentTitle, bool flag= true)
{
var pdfPrintQueue = GetMicrosoftPdfPrintQueue();
var ptrUnmanagedBytes = Marshal.AllocCoTaskMem(bytes.Length);
Marshal.Copy(bytes, 0, ptrUnmanagedBytes, bytes.Length);
var di = new DOCINFOA
{
pDocName = documentTitle,
pOutputFile = outputFilePath,
pDataType = "RAW"
};
var errorCode = SendBytesToPrinter(pdfPrintQueue.Name, ptrUnmanagedBytes, bytes.Length, di, out var jobId, flag);
Marshal.FreeCoTaskMem(ptrUnmanagedBytes);
}
private int SendBytesToPrinter(string szPrinterName, IntPtr pBytes, int dwCount, DOCINFOA documentInfo, out int jobId, bool flag= true)
{
jobId = 0;
var dwWritten = 0;
var success = false;
if (OpenPrinter(szPrinterName.Normalize(), out var hPrinter, IntPtr.Zero))
{
jobId = StartDocPrinter(hPrinter, 1, documentInfo);
if (jobId > 0)
{
if (StartPagePrinter(hPrinter))
{
success = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
}
}
ClosePrinter(hPrinter);
}
if (success == false)
{
return Marshal.GetLastWin32Error();
}
return 0;
}
[DllImport("winspool.drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int StartDocPrinter(IntPtr hPrinter, int level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, int dwCount, out int dwWritten);
本文由 caroly 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载 / 出处外,均为本站原创或翻译,转载前请务必署名
原文链接:https://caroly.fun/archives/wpf导出pdf
最后更新:2021-04-29 14:44:37
Update your browser to view this website correctly. Update my browser now