WPF PDF Viewer C# Library
How to view PDF file directly in C# WPF (Core) Windows application?
Complete step by step tutorial to view PDF pages with navigation, zooming in WPF Windows application using C#.
In WPF winodws application development, you will need enable users to view PDF files directly on WPF window. This WPF tutorial teachs how to view a PDF file in WPF window using XDoc.PDF C# library.
At the end of the tutorial, you'll have a WPF window app that reads and displays a PDF document on WPF window. You will learn how to:
- Create a WPF app
- View a PDF page content on Window
- Navigate PDF pages content
- Adjust page view size
Download and Install XDoc.PDF WPF C# library
How to view PDF on Windows using C# in WPF (.NET Core) application?
1. Create a new WPF (.NET Core) project with XDoc.PDF C# library
Here we will create a new WPF project with name "REPDFViewerWPFDemo".
We have provided step by step guide to install XDoc.PDF library on a new WPF (.NET Core) project. Please view here:
How to create a new WPF app using Visual Studio 2022 to process PDF?
2. Design the WPF Window user interface
Select MainWindow.xaml in the Solution Explorer to open the WPF Designer.
XAML View
Design View
2.1 Adjust the attributes of the Window tag as below.
XAML
<Window x:Class="REPDFViewerWPFDemo.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:local="clr-namespace:REPDFViewerWPFDemo"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="700" WindowStartupLocation="CenterScreen">
<Grid>
</Grid>
</Window>
2.2 Split main panel to View panel () and View Setting panel ().
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid Name="View" Grid.Row="0" Background="DarkGray" />
<DockPanel Grid.Row="1">
</DockPanel>
</Grid>
Design View
2.3 Add a Button control and two ComboBox controls to the View Setting panel.
XAML
<DockPanel Grid.Row="1">
<Button Content="Open File" Width="100" Margin="12,12,12,12" />
<StackPanel Width="264" Orientation="Horizontal" HorizontalAlignment="Right">
<ComboBox Name="PageNumber" Width="80" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False" />
<ComboBox Name="ViewMode" Width="135" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False">
<ComboBoxItem Content="Actual Size"/>
<ComboBoxItem Content="Zoom to Page Level"/>
<ComboBoxItem Content="Fit Width"/>
</ComboBox>
</StackPanel>
</DockPanel>
Design View
2.4 Add an Image control to the view panel with a ScrollViewer control.
XAML
<Grid Name="View" Grid.Row="0" Background="DarkGray">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<Image Name="PageImage" Height="100" Width="100"/>
</ScrollViewer>
</Grid>
Design View
3. Add event handler to controls
3.1 add "Click" event handler for the Button control with name "Button_Click".
XAML (old)
<Button Content="Open File" Width="100" Margin="12,12,12,12" />
XAML (new)
<Button Content="Open File" Width="100" Margin="12,12,12,12"
Click="Button_Click" />
3.2 add "DropDownClosed" event handler to two ComboBox controls with name "PageNumber_DropDownClosed" and "ViewMode_DropDownClosed".
XAML (old)
<ComboBox Name="PageNumber" Width="80" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False" />
<ComboBox Name="ViewMode" Width="135" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False">
XAML (new)
<ComboBox Name="PageNumber" Width="80" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False"
DropDownClosed="PageNumber_DropDownClosed" />
<ComboBox Name="ViewMode" Width="135" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False"
DropDownClosed="ViewMode_DropDownClosed">
3.3 add "SizeChanged" event handler to the view panel with name "StackPanel_SizeChanged".
XAML (old)
<Grid Name="View" Grid.Row="0" Background="DarkGray">
Finally, the XAML markup should look like to the below.
MainWindow.xaml
<Window x:Class="REPDFViewerWPFDemo.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:local="clr-namespace:REPDFViewerWPFDemo"
mc:Ignorable="d"
Title="MainWindow" Height="800" Width="700" WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid Name="View" Grid.Row="0" Background="DarkGray"
SizeChanged="StackPanel_SizeChanged">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<Image Name="PageImage" Height="100" Width="100"/>
</ScrollViewer>
</Grid>
<DockPanel Grid.Row="1">
<Button Content="Button" Width="100" Margin="12,12,12,12"
Click="Button_Click" />
<StackPanel Width="264" Orientation="Horizontal" HorizontalAlignment="Right">
<ComboBox Name="PageNumber" Width="80" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False"
DropDownClosed="PageNumber_DropDownClosed" />
<ComboBox Name="ViewMode" Width="135" Margin="12,12,12,12" DockPanel.Dock="Right"
IsEnabled="False"
DropDownClosed="ViewMode_DropDownClosed">
<ComboBoxItem Content="Actual Size"/>
<ComboBoxItem Content="Zoom to Page Level"/>
<ComboBoxItem Content="Fit Width"/>
</ComboBox>
</StackPanel>
</DockPanel>
</Grid>
</Window>
4. Add code to the main window.
Replace all contents in the "MainWindow.xaml.cs" file by following codes.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.IO;
using System.Drawing;
using Microsoft.Win32;
using RasterEdge.Imaging.Basic;
using RasterEdge.XDoc.PDF;
namespace REPDFViewerWPFDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private String _targetFilePath = "";
private String _currPageViewMode;
private Bitmap _cachedPageImage = new Bitmap(1, 1);
private float _cachedPageZoomRatio = 4F;
public MainWindow()
{
InitializeComponent();
this._currPageViewMode = this.ViewMode.Text;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "PDF files (*.pdf)|*.pdf";
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() ?? false)
{
try
{
String filePath = openFileDialog.FileName;
if (String.IsNullOrEmpty(filePath))
throw new Exception("Target file path is null or empty.");
if (!File.Exists(filePath))
throw new Exception("Target file does not exist.");
PDFDocument doc = new PDFDocument(filePath);
int pageCount = doc.GetPageCount();
if (pageCount <= 0)
throw new Exception("Load PDF file failed. Page count must be positive.");
setAndEnableViewSettingControls(pageCount);
this._targetFilePath = filePath;
this._currPageViewMode = this.ViewMode.Text;
this.Title = filePath;
updateCachedPageImage(this.PageNumber.SelectedIndex);
updatePageView();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
private void PageNumber_DropDownClosed(object sender, EventArgs e)
{
updateCachedPageImage(this.PageNumber.SelectedIndex);
updatePageView();
}
private void ViewMode_DropDownClosed(object sender, EventArgs e)
{
this._currPageViewMode = this.ViewMode.Text;
updatePageView();
}
private void StackPanel_SizeChanged(object sender, SizeChangedEventArgs e)
{
updatePageView();
}
private void setAndEnableViewSettingControls(int pageCount)
{
this.PageNumber.Items.Clear();
for (int i = 1; i <= pageCount; i++)
{
ComboBoxItem item = new ComboBoxItem();
item.Content = "Page " + i;
this.PageNumber.Items.Add(item);
}
this.PageNumber.SelectedIndex = 0;
this.PageNumber.IsEnabled = true;
this.ViewMode.SelectedIndex = 0;
this.ViewMode.IsEnabled = true;
}
public bool HasTargetFile
{
get { return !String.IsNullOrEmpty(this._targetFilePath); }
}
private void updateCachedPageImage(int pageIndex)
{
if (!HasTargetFile) return;
try
{
PDFDocument doc = new PDFDocument(this._targetFilePath);
BasePage page = doc.GetPage(pageIndex);
// Get page size in inch.
float pageWidth = page.GetWidth();
float pageHeight = page.GetHeight();
// Zoom ratio used in page renderring.
// Default: 4
float zoomRatio = 4F;
// Set to small value if page size is too large.
if (pageWidth > 12F || pageHeight > 12F)
zoomRatio = 2;
else if (pageWidth > 20F || pageHeight > 20F)
zoomRatio = 1;
Bitmap image = page.GetBitmap(zoomRatio);
setCachecPageImage(image, zoomRatio);
}
catch (Exception)
{
setCachecPageImage(new Bitmap(1, 1), 4F);
}
}
private void setCachecPageImage(Bitmap image, float zoomRatio)
{
this._cachedPageImage = image;
this._cachedPageZoomRatio = zoomRatio;
}
private void updatePageView()
{
if (!HasTargetFile)
return;
if (this._cachedPageImage == null)
return;
try
{
float canvasWidth = (float)this.View.ActualWidth - 20;
float canvasHeight = (float)this.View.ActualHeight;
// Estimate show image size.
float imageWidth = this._cachedPageImage.Width;
float imageHeight = this._cachedPageImage.Height;
float zoomRatio = 1F;
switch (this._currPageViewMode)
{
case "Zoom to Page Level":
zoomRatio = Math.Min(canvasWidth / imageWidth, canvasHeight / imageHeight);
break;
case "Fit Width":
zoomRatio = canvasWidth / imageWidth;
break;
case "Actual Size":
zoomRatio = 1F / this._cachedPageZoomRatio;
break;
default:
break;
}
imageWidth *= zoomRatio;
imageHeight *= zoomRatio;
Bitmap bitmap = new Bitmap((int)imageWidth, (int)imageHeight);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(this._cachedPageImage, 0, 0, bitmap.Width, bitmap.Height);
}
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.EndInit();
this.PageImage.Width = imageWidth;
this.PageImage.Height = imageHeight;
this.PageImage.Source = bi;
}
}
catch (Exception)
{
}
}
}
}
5. It is done. Now press "Ctrl+F5" to run the WPF project.
6. Screenshot for the WPF PDF Viewer demo application.
Press "Open File" button to choose a PDF file through the open file dialog. Then, it shows the first page of the selected PDF file in "Actual Size" mode.
Use two ComboBox controls to change page number and view mode.
Conclusion
Here you have successfully created a new WPF Window application to read, view, navigate PDF file pages. It is a simple demo project. You can further
improve it by performance tuning, more PDF view, navigate, search features.
RasterEdge provides mature ASP.NET PDF Viewer and Editor web control, you could view the details here:
How to view, edit PDF file in web browser using C# ASP.NET?