# PDF 查看与打印模块使用指南 | PDF Viewer & Printer Module Usage Guide ## 概述 | Overview `XP.Common.PdfViewer` 提供基于 Telerik RadPdfViewer 的 PDF 文件查看与打印功能模块。模块作为 XP.Common 的通用可复用组件,通过 Prism DI 容器注册服务接口,供外部类库通过构造函数注入使用。 ### 核心功能 | Core Features - PDF 文件加载与显示(支持文件路径和文件流两种方式) - 内置 RadPdfViewerToolbar 提供页面导航、缩放、旋转、打印等完整工具栏 UI - 静默打印(指定打印机、页面范围、打印份数) - 打印设置对话框(用户交互式配置打印参数) - 打印预览功能 - 多语言支持(简体中文、繁体中文、英文) - 结构化日志记录(使用 ILoggerService) - 资源自动释放(IDisposable + 终结器安全网) --- ## 目录结构 | Directory Structure ``` XP.Common/PdfViewer/ ├── Exceptions/ # 自定义异常 │ ├── PdfLoadException.cs # PDF 加载异常 │ ├── PrinterNotFoundException.cs # 打印机未找到异常 │ └── PrintException.cs # 打印异常 ├── Interfaces/ # 服务接口 │ ├── IPdfViewerService.cs # PDF 查看服务接口 │ └── IPdfPrintService.cs # PDF 打印服务接口 ├── Implementations/ # 服务实现 │ ├── PdfViewerService.cs # PdfViewerService 实现 │ └── PdfPrintService.cs # PdfPrintService 实现 ├── ViewModels/ # ViewModel │ └── PdfViewerWindowViewModel.cs # 阅读器窗口 ViewModel └── Views/ # 视图 ├── PdfViewerWindow.xaml # 阅读器窗口 XAML └── PdfViewerWindow.xaml.cs # 阅读器窗口 Code-Behind ``` --- ## 服务接口 | Service Interfaces ### IPdfViewerService - PDF 查看服务 负责 PDF 文件加载和阅读器窗口管理。 ```csharp public interface IPdfViewerService : IDisposable { /// 通过文件路径打开 PDF 阅读器窗口 void OpenViewer(string filePath); /// 通过文件流打开 PDF 阅读器窗口 void OpenViewer(Stream stream, string? title = null); } ``` ### IPdfPrintService - PDF 打印服务 负责 PDF 打印功能,包括静默打印和交互式打印。 ```csharp public interface IPdfPrintService { /// 使用指定打印机打印 PDF 文件 void Print(string filePath, string printerName, int? pageFrom = null, int? pageTo = null, int copies = 1); /// 打开打印设置对话框并打印 bool PrintWithDialog(string filePath); /// 打开打印预览对话框 void PrintPreview(string filePath); } ``` --- ## 使用示例 | Usage Examples ### 1. 通过文件路径打开 PDF ```csharp using XP.Common.PdfViewer.Interfaces; public class MyService { private readonly IPdfViewerService _pdfViewerService; public MyService(IPdfViewerService pdfViewerService) { _pdfViewerService = pdfViewerService; } public void OpenPdfByPath() { // 打开指定路径的 PDF 文件 _pdfViewerService.OpenViewer(@"C:\Documents\UserManual.pdf"); } } ``` ### 2. 通过文件流打开 PDF ```csharp public void OpenPdfByStream() { // 从文件流打开 PDF(窗口标题可选) using var stream = File.OpenRead(@"C:\Documents\UserManual.pdf"); _pdfViewerService.OpenViewer(stream, "用户手册.pdf"); } ``` ### 3. 静默打印到指定打印机 ```csharp using XP.Common.PdfViewer.Interfaces; public class MyService { private readonly IPdfPrintService _printService; public MyService(IPdfPrintService printService) { _printService = printService; } public void PrintPdf() { // 打印全部页面到指定打印机 _printService.Print( filePath: @"C:\Documents\UserManual.pdf", printerName: "HP LaserJet Pro", pageFrom: null, // null 表示从第一页 pageTo: null, // null 表示到最后一页 copies: 1 // 打印 1 份 ); // 打印指定范围(第 1-3 页) _printService.Print( filePath: @"C:\Documents\UserManual.pdf", printerName: "HP LaserJet Pro", pageFrom: 1, pageTo: 3, copies: 2 ); } } ``` ### 4. 打开打印设置对话框 ```csharp public void OpenPrintDialog() { // 显示打印设置对话框,用户确认后打印 bool userConfirmed = _printService.PrintWithDialog(@"C:\Documents\UserManual.pdf"); if (userConfirmed) { // 用户点击了"确定"按钮 } else { // 用户点击了"取消"按钮 } } ``` ### 5. 打开打印预览 ```csharp public void ShowPrintPreview() { // 打开打印预览对话框 _printService.PrintPreview(@"C:\Documents\UserManual.pdf"); } ``` --- ## DI 注册 | DI Registration 在 `CommonModule.RegisterTypes` 中已注册为单例服务: ```csharp containerRegistry.RegisterSingleton(); containerRegistry.RegisterSingleton(); ``` 在 ViewModel 或 Service 中通过构造函数注入使用: ```csharp public class MyViewModel { private readonly IPdfViewerService _pdfViewerService; private readonly IPdfPrintService _printService; public MyViewModel( IPdfViewerService pdfViewerService, IPdfPrintService printService) { _pdfViewerService = pdfViewerService; _printService = printService; } } ``` --- ## 多语言资源 | Localization Resources PDF 模块支持多语言,资源键如下: | 资源键 | zh-CN | zh-TW | en-US | |--------|-------|-------|-------| | `PdfViewer_Title` | PDF 阅读器 | PDF 閱讀器 | PDF Viewer | | `PdfViewer_TitleWithFile` | PDF 阅读器 - {0} | PDF 閱讀器 - {0} | PDF Viewer - {0} | | `PdfViewer_LoadSuccess` | PDF 文件加载成功:{0}({1} 页)| PDF 檔案載入成功:{0}({1} 頁)| PDF loaded: {0} ({1} pages) | | `PdfViewer_LoadFailed` | PDF 文件加载失败 | PDF 檔案載入失敗 | PDF file load failed | | `PdfViewer_PrintSuccess` | 打印任务已提交:{0} → {1} | 列印任務已提交:{0} → {1} | Print job submitted: {0} → {1} | | `PdfViewer_PrintFailed` | 打印失败 | 列印失敗 | Print failed | | `PdfViewer_PrinterNotFound` | 打印机未找到:{0} | 印表機未找到:{0} | Printer not found: {0} | --- ## 异常处理 | Exception Handling | 异常类型 | 触发条件 | 说明 | |---------|---------|------| | `FileNotFoundException` | 文件路径不存在 | `OpenViewer(filePath)` 或 `Print(filePath, ...)` | | `ArgumentNullException` | 流参数为 null | `OpenViewer(null, ...)` | | `PdfLoadException` | PDF 格式无效或加载失败 | 文件损坏、非 PDF 格式等 | | `PrinterNotFoundException` | 指定打印机不存在 | `Print(filePath, printerName, ...)` | | `PrintException` | 打印过程中发生错误 | 打印机错误、驱动问题等 | --- ## 注意事项 | Notes 1. **RadPdfViewerToolbar 内置功能**:页面导航(首页/上一页/下一页/末页)、缩放(放大/缩小/适合宽度/适合整页)、旋转(顺时针/逆时针)等功能由 RadPdfViewerToolbar 自动提供,无需手动实现。 2. **资源释放**:`PdfViewerService` 实现 `IDisposable`,窗口��闭时会自动释放 PDF 文档资源。终结器作为安全网,确保未显式释放时也能清理资源。 3. **多语言支持**:RadPdfViewerToolbar 的内置按钮文本(如"首页"、"上一页"、"放大"等)由 Telerik 自身的本地化机制管理,无需在 XP.Common 的 Resources 中维护。 4. **打印设置**:Telerik 提供内置的 `PrintSettings` 类,无需自定义打印设置模型。 5. **日志记录**:所有关键操作(加载成功/失败、打印成功/失败)都会通过 `ILoggerService` 记录结构化日志。 --- ## 典型应用场景 | Typical Use Cases ### 场景 1:主窗口添加"用户手册"按钮 ```csharp // MainWindowViewModel.cs private void ExecuteOpenUserManual() { var manualPath = ConfigurationManager.AppSettings["UserManual"]; var stream = File.OpenRead(manualPath); var fileName = Path.GetFileName(manualPath); _pdfViewerService.OpenViewer(stream, fileName); } ``` ### 场景 2:导出报告后自动打开 PDF 预览 ```csharp public void ExportAndPreview() { // 生成 PDF 报告到临时文件 var tempPath = Path.Combine(Path.GetTempPath(), $"Report_{DateTime.Now:yyyyMMdd_HHmmss}.pdf"); GenerateReport(tempPath); // 自动打开 PDF 预览 _pdfViewerService.OpenViewer(tempPath); } ``` ### 场景 3:批量打印检测报告 ```csharp public void BatchPrintReports(List reportPaths, string printerName) { foreach (var path in reportPaths) { _printService.Print( filePath: path, printerName: printerName, pageFrom: 1, pageTo: null, copies: 1 ); } } ```