300 lines
9.0 KiB
Markdown
300 lines
9.0 KiB
Markdown
# 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<IPdfPrintService, PdfPrintService>();
|
||
containerRegistry.RegisterSingleton<IPdfViewerService, PdfViewerService>();
|
||
```
|
||
|
||
在 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<string> reportPaths, string printerName)
|
||
{
|
||
foreach (var path in reportPaths)
|
||
{
|
||
_printService.Print(
|
||
filePath: path,
|
||
printerName: printerName,
|
||
pageFrom: 1,
|
||
pageTo: null,
|
||
copies: 1
|
||
);
|
||
}
|
||
}
|
||
```
|