在C# WPF项目中集成PDF查看器的两种方法

 更新时间:2025年12月29日 09:40:09   作者:꧁༺℘₨风、凌๓༻꧂  
文章介绍了在WPF中使用PdfiumViewer控件的两种方法:通过NuGet包安装并手动创建控件,创建自定义WPF控件,文章还解决了在WPF中使用PdfiumViewer时可能出现的常见问题,需要的朋友可以参考下

方法1:通过 NuGet 包安装并手动创建控件(推荐)

1. 安装 NuGet 包

<!-- 在你的 WPF 项目的 .csproj 文件中添加 -->
<PackageReference Include="PdfiumViewer" Version="2.11.0" />
<PackageReference Include="PdfiumViewer.Native.x86_64.v8-xfa" Version="2023.6.12.1" />

或通过 NuGet 包管理器控制台:

Install-Package PdfiumViewer
Install-Package PdfiumViewer.Native.x86_64.v8-xfa

2. 在 XAML 中设置 WindowsFormsHost

由于 PdfiumViewer 是 WinForms 控件,需要在 WPF 中使用 WindowsFormsHost

<!-- 在 MainWindow.xaml 中 -->
<Window x:Class="YourNamespace.MainWindow"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        mc:Ignorable="d"
        Title="PDF Viewer" Height="600" Width="800">
    
    <Grid>
        <WindowsFormsHost x:Name="pdfHost" Margin="10"/>
    </Grid>
</Window>

3. 在代码后台创建和使用 PdfViewer

using System;
using System.Windows;
using PdfiumViewer;
using System.Windows.Forms.Integration;

namespace YourNamespace
{
    public partial class MainWindow : Window
    {
        private PdfViewer pdfViewer;
        
        public MainWindow()
        {
            InitializeComponent();
            InitializePdfViewer();
        }
        
        private void InitializePdfViewer()
        {
            // 创建 PdfViewer 实例
            pdfViewer = new PdfViewer();
            pdfViewer.Dock = System.Windows.Forms.DockStyle.Fill;
            
            // 将 PdfViewer 添加到 WindowsFormsHost
            pdfHost.Child = pdfViewer;
        }
        
        // 打开 PDF 文件
        private void OpenPdf(string filePath)
        {
            try
            {
                // 加载 PDF 文档
                pdfViewer.Document = PdfDocument.Load(filePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"打开 PDF 失败: {ex.Message}");
            }
        }
        
        // 示例:在窗口加载时打开 PDF
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            OpenPdf(@"C:\path\to\your\document.pdf");
        }
    }
}

方法2:创建自定义 WPF 控件(更优雅)

1. 创建 PdfViewerWrapper 用户控件

<!-- PdfViewerWrapper.xaml -->
<UserControl x:Class="YourNamespace.Controls.PdfViewerWrapper"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <WindowsFormsHost x:Name="host"/>
    </Grid>
</UserControl>
// PdfViewerWrapper.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using PdfiumViewer;
using System.Windows.Forms.Integration;

namespace YourNamespace.Controls
{
    public partial class PdfViewerWrapper : UserControl
    {
        private PdfViewer pdfViewer;
        
        public PdfViewerWrapper()
        {
            InitializeComponent();
            InitializePdfViewer();
        }
        
        private void InitializePdfViewer()
        {
            pdfViewer = new PdfViewer
            {
                Dock = System.Windows.Forms.DockStyle.Fill
            };
            host.Child = pdfViewer;
        }
        
        // 打开 PDF 文件
        public void LoadPdf(string filePath)
        {
            try
            {
                pdfViewer.Document = PdfDocument.Load(filePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载 PDF 失败: {ex.Message}");
            }
        }
        
        // 从字节数组加载
        public void LoadPdf(byte[] pdfData)
        {
            try
            {
                pdfViewer.Document = PdfDocument.Load(pdfData);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载 PDF 失败: {ex.Message}");
            }
        }
        
        // 从流加载
        public void LoadPdf(System.IO.Stream stream)
        {
            try
            {
                pdfViewer.Document = PdfDocument.Load(stream);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载 PDF 失败: {ex.Message}");
            }
        }
        
        // 获取当前页面索引
        public int GetCurrentPage()
        {
            return pdfViewer?.Renderer?.Page ?? 0;
        }
        
        // 跳转到指定页面
        public void GoToPage(int page)
        {
            if (pdfViewer?.Renderer != null && page >= 0 && page < pdfViewer.Document.PageCount)
            {
                pdfViewer.Renderer.Page = page;
            }
        }
    }
}

2. 在主窗口中使用自定义控件

<!-- MainWindow.xaml -->
<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="clr-namespace:YourNamespace.Controls"
        Title="PDF Viewer" Height="600" Width="800">
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <!-- 工具栏 -->
        <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10">
            <Button Content="打开 PDF" Click="OpenPdfButton_Click" Margin="5"/>
            <Button Content="上一页" Click="PrevPageButton_Click" Margin="5"/>
            <Button Content="下一页" Click="NextPageButton_Click" Margin="5"/>
            <TextBlock Text="页码:" VerticalAlignment="Center" Margin="10,0,5,0"/>
            <TextBlock x:Name="pageInfo" VerticalAlignment="Center"/>
        </StackPanel>
        
        <!-- PDF 查看器 -->
        <controls:PdfViewerWrapper x:Name="pdfViewerControl" Grid.Row="1"/>
    </Grid>
</Window>
// MainWindow.xaml.cs
using Microsoft.Win32;
using System.Windows;

namespace YourNamespace
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        
        private void OpenPdfButton_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Filter = "PDF 文件|*.pdf|所有文件|*.*",
                Title = "选择 PDF 文件"
            };
            
            if (openFileDialog.ShowDialog() == true)
            {
                pdfViewerControl.LoadPdf(openFileDialog.FileName);
            }
        }
        
        private void PrevPageButton_Click(object sender, RoutedEventArgs e)
        {
            int currentPage = pdfViewerControl.GetCurrentPage();
            if (currentPage > 0)
            {
                pdfViewerControl.GoToPage(currentPage - 1);
            }
        }
        
        private void NextPageButton_Click(object sender, RoutedEventArgs e)
        {
            int currentPage = pdfViewerControl.GetCurrentPage();
            pdfViewerControl.GoToPage(currentPage + 1);
        }
    }
}

方法3:使用 PdfRenderer 而不是 PdfViewer

如果你只需要简单的 PDF 渲染(没有工具栏),可以使用 PdfRenderer

using System.Windows;
using System.Windows.Forms.Integration;
using PdfiumViewer;

public partial class MainWindow : Window
{
    private PdfRenderer pdfRenderer;
    
    public MainWindow()
    {
        InitializeComponent();
        InitializePdfRenderer();
    }
    
    private void InitializePdfRenderer()
    {
        pdfRenderer = new PdfRenderer();
        pdfRenderer.Dock = System.Windows.Forms.DockStyle.Fill;
        pdfRenderer.ZoomMode = PdfViewerZoomMode.FitWidth;
        
        // 添加到 WindowsFormsHost
        var host = new WindowsFormsHost();
        host.Child = pdfRenderer;
        
        // 添加到 WPF 容器
        contentContainer.Children.Add(host);
    }
    
    private void LoadPdf(string filePath)
    {
        var document = PdfDocument.Load(filePath);
        pdfRenderer.Load(document);
    }
}

解决常见问题

问题1:找不到 PdfiumViewer 控件

  • 原因:PdfiumViewer 是 WinForms 控件,不会自动出现在 WPF 工具箱中
  • 解决方案:手动创建控件实例,如上所示

问题2:运行时异常(DLL 未找到)

<!-- 在 .csproj 中确保包含 Native 包 -->
<PackageReference Include="PdfiumViewer.Native.x86_64.v8-xfa" Version="2023.6.12.1" />
<!-- 或 x86 版本 -->
<PackageReference Include="PdfiumViewer.Native.x86.v8-xfa" Version="2023.6.12.1" />

问题3:设计时看不到控件

  • 原因:WinForms 控件在 WPF 设计器中不可见
  • 解决方案:在设计时显示占位符,运行时加载真实控件
<!-- 在设计时显示标签,运行时替换 -->
<UserControl>
    <Grid>
        <TextBlock x:Name="designText" 
                   Text="PDF Viewer (设计时)"
                   Visibility="{Binding IsInDesignMode, Converter={StaticResource BoolToVisibilityConverter}}"/>
        <WindowsFormsHost x:Name="host" 
                          Visibility="{Binding IsInDesignMode, Converter={StaticResource BoolToVisibilityInverseConverter}}"/>
    </Grid>
</UserControl>

完整示例项目结构

YourSolution/
├── YourWpfProject/
│   ├── Controls/
│   │   ├── PdfViewerWrapper.xaml
│   │   └── PdfViewerWrapper.xaml.cs
│   ├── MainWindow.xaml
│   ├── MainWindow.xaml.cs
│   └── YourWpfProject.csproj
└── YourWpfProject.sln

在工具箱中手动添加控件(可选)

虽然不能直接拖拽,但你可以:

  1. 创建自定义控件库:将 PdfViewerWrapper 控件编译为独立的 DLL
  2. 添加到工具箱
    • 右键点击工具箱 → “选择项”
    • 浏览并选择你的控件 DLL
    • 控件将出现在工具箱中

总结

在 WPF 中使用 PdfiumViewer 的关键步骤:

  1. 安装 NuGet 包:PdfiumViewer 及其 Native 包
  2. 使用 WindowsFormsHost:承载 WinForms 控件
  3. 代码创建控件:在代码后台或自定义用户控件中实例化 PdfViewer
  4. 加载 PDF:使用 PdfDocument.Load() 方法

虽然不能像 WinForms 那样直接在工具箱中拖拽,但通过创建自定义用户控件,你可以在 WPF 中获得类似的开发体验。

以上就是在C# WPF项目中集成PDF查看器的两种方法的详细内容,更多关于C# WPF集成PDF查看器的资料请关注脚本之家其它相关文章!

相关文章

  • C#递归算法之归并排序

    C#递归算法之归并排序

    这篇文章主要介绍了C#递归算法中的归并排序,需要的朋友可以参考下。
    2016-06-06
  • C#实现Ruby的负数索引器

    C#实现Ruby的负数索引器

    这篇文章主要介绍了C#实现Ruby的负数索引器的相关代码和使用方法,非常简单实用,需要的朋友可以参考下
    2016-07-07
  • C#开发答题赢钱游戏(自动答题器)

    C#开发答题赢钱游戏(自动答题器)

    现在最火的直播游戏,那就是答题赢钱直播了,如百万英雄、芝士超人、花椒直播、冲顶大会等等,这些游戏的玩法都很简单,答对12题即可瓜分奖金了。玩法虽简单但是完全答对12题难度就挺高了,下面小编给大家带来了C#开发答题赢钱游戏,需要的朋友参考下吧
    2018-01-01
  • C#通过经纬度计算2个点之间距离的实现代码

    C#通过经纬度计算2个点之间距离的实现代码

    这篇文章主要介绍了C#通过经纬度计算2个点之间距离实现代码,本文对实现原理、经纬度基本知识等一并做了讲解,需要的朋友可以参考下
    2014-08-08
  • C#内存泄漏的四个常见场景及其解决办法

    C#内存泄漏的四个常见场景及其解决办法

    文章详解C#内存泄漏四大解决策略:资源释放(using语句)、事件订阅管理、静态集合控制及工具分析,辅以对象池等高级技巧,助开发者精准定位并优化内存使用
    2025-05-05
  • Unity C#打包AssetBundle与场景详解

    Unity C#打包AssetBundle与场景详解

    这篇文章主要给大家介绍了关于Unity C#打包AssetBundle与场景的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-02-02
  • C#私有构造函数使用示例

    C#私有构造函数使用示例

    本文主要介绍了C#私有构造函数使用方法,私有构造函数是一种特殊的实例构造函数。它通常用在只包含静态成员的类中。如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例
    2014-01-01
  • C#条件编译、内联函数、CLS介绍

    C#条件编译、内联函数、CLS介绍

    这篇文章介绍了C#的条件编译、内联函数、CLS,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • C# 总结QueueUserWorkItem传参几种方式案例详解

    C# 总结QueueUserWorkItem传参几种方式案例详解

    这篇文章主要介绍了C# 总结QueueUserWorkItem传参几种方式案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • protobuf对象二进制序列化存储(详解)

    protobuf对象二进制序列化存储(详解)

    下面小编就为大家带来一篇protobuf对象二进制序列化存储(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02

最新评论