如何在WPF中从DLL读取PDF并在Adobe PDF Reader控件显示?
解决WPF中加载DLL嵌入PDF的问题
你遇到的核心问题是:Adobe的AxAcroPDF控件不支持WPF的pack URI格式——它是基于WinForms的ActiveX控件,只能识别标准的本地文件系统路径,或者通过间接方式加载(比如先把嵌入的资源转成临时文件)。下面给你两种可行的解决方案,按需选择:
方法一:将嵌入PDF提取到临时文件加载
这是适配现有AxAcroPDF控件的快速方案,步骤如下:
- 确认资源配置:首先确保DLL中的PDF文件在Visual Studio里的生成操作设置为「嵌入的资源」,否则程序无法读取到资源。
- 读取嵌入资源流:通过程序集获取资源的流,注意资源名称的格式是「命名空间.文件夹路径.文件名.pdf」(比如你的项目命名空间是
SampleClass,PDF放在PDFs文件夹下,那资源名就是SampleClass.PDFs.xxx.pdf)。 - 写入临时文件并加载:把流复制到系统临时文件夹的临时文件,再用AxAcroPDF加载这个路径,最后记得在窗口关闭时清理临时文件。
示例代码:
using System.Reflection; using System.IO; using System.Windows; // 获取包含PDF资源的程序集(如果PDF在当前运行的程序集里就用GetExecutingAssembly,否则替换为对应的Assembly) var assembly = Assembly.GetExecutingAssembly(); // 替换成你的实际资源名称,注意大小写和路径 var resourceName = "SampleClass.PDFs.YourTargetPDF.pdf"; using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { if (resourceStream == null) { MessageBox.Show("未找到指定的PDF嵌入资源,请检查资源名称是否正确"); return; } // 创建唯一的临时PDF文件,避免冲突 string tempPdfPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.pdf"); // 将资源流写入临时文件 using (FileStream tempFileStream = new FileStream(tempPdfPath, FileMode.Create)) { resourceStream.CopyTo(tempFileStream); } // 加载PDF到Acrobat控件 axAcroPDF1.LoadFile(tempPdfPath); // 窗口关闭时清理临时文件(忽略删除失败的情况,比如文件被占用) this.Closed += (sender, e) => { if (File.Exists(tempPdfPath)) { try { File.Delete(tempPdfPath); } catch { } } }; }
小提示
如果不确定资源名称,可以用assembly.GetManifestResourceNames()列出所有嵌入资源,找到你要的PDF对应的名称。
方法二:换用支持流加载的PDF控件(更安全高效)
如果不想依赖临时文件(避免磁盘残留敏感内容),推荐使用支持直接从流加载PDF的WPF/WinForms控件,比如:
- PdfiumViewer:开源免费,支持WPF(通过
WindowsFormsHost嵌入),可以直接加载流。 - Syncfusion PdfViewer:商业控件,功能更丰富,原生支持WPF和流加载。
以PdfiumViewer为例,示例代码(需要先安装NuGet包PdfiumViewer):
using System.Reflection; using System.IO; using PdfiumViewer; var assembly = Assembly.GetExecutingAssembly(); var resourceName = "SampleClass.PDFs.YourTargetPDF.pdf"; using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { if (resourceStream != null) { // 创建PdfViewer控件并加载流 var pdfViewer = new PdfViewer(); pdfViewer.Load(resourceStream); // 嵌入到WPF的WindowsFormsHost中(需要在XAML里先添加WindowsFormsHost控件) windowsFormsHost.Child = pdfViewer; } }
这种方式不需要生成临时文件,更符合你“避免外部访问”的需求,也更整洁。
内容的提问来源于stack exchange,提问作者Dante123




