Intro
Hello and Welcome to a new Tutorial, This is going to be another special tutorial that is sponsored by this amazing company called Syncfusion!.
.NET, Xamarin, JavaScript, Angular UI components | Syncfusion
What is Syncfusion ?
It is the World’s Best UI Component Suite for Building Powerful Web, Desktop, and Mobile Apps.
In this tutorial, we will be building a Desktop app that converts PDF files to different formats, and we will be using the libraries offered by Syncfusion to achieve that.
We will use their File Converting libraries as well as one of their responsive themes to make our app look amazing :).
So let’s get started!.
Setting up our Project
—Create a new WPF project—
—Add the following Nuget Packages—
So let’s look at what we have imported.
To be able to convert from Doc(word)to PDF we will need the following Package.
-Syncfusion.DocToPDFConverter.Wpf
To create and Manipulate PDF documents we will need the following Package.
-Syncfusion.Pdf.Wpf
To use the basic Syncfusion UI elements like buttons etc we will need the following package.
-Syncfusion.Shared.WPF
To manage our themes we will add the syncfusion theme manager.
-Syncfusion.SfSkinManager.WPF
And finally, we will add the theme that we will be using which is the Fluent Light theme, and here fluent means that it is responsive.
Syncfusion.Themes.FluentLight.WPF
An additional Nuget package that we will need to work with graphics and images(Not from Syncfusion).
System.Drawing.Common
In the MainWindow.xaml.cs we will need the following namespaces.
using Microsoft.Win32; //to work with word documents using Syncfusion.DocIO; using Syncfusion.DocIO.DLS; using Syncfusion.DocToPDFConverter; //to read convert and work with PDF files using Syncfusion.Pdf; using Syncfusion.Pdf.Graphics; using Syncfusion.Pdf.Parsing; //for our theme using Syncfusion.SfSkinManager; using Syncfusion.Themes.FluentLight.WPF; //to start a proccess we need the diagnostics namespace using System.Diagnostics; //to work with images using System.Drawing; //to save and read files using System.IO; using System.Windows;
Now we need to also import a few assets which are icons for our buttons and our logo.
Create a new folder called Images
Add the following images to it.
Make sure that all images are configured correctly like so.
We set the Build Action to Resource and Copy to our Directory if newer, This is to make sure that our images will appear correctly in our UI.
Now let’s start building our UI.
First let’s change the size of our window and add our icon.
Resizing our UI
We will also add a dependency property to our grid which we will link to a grid layout transform that we will use in the code behind to adjust our UI scale when the window size changes!, We will call this property ScaleValue.
Also we need to add an event to our gird for when the size of the grid changes, later on we will use this event to calculate the new size of our gird.
In our MainWindow.Xaml
<Window 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:PDFConverterV2" xmlns:System="clr-namespace:System;assembly=netstandard" xmlns:syncfusion="http://schemas.syncfusion.com/wpf" x:Class="PDFConverterV2.MainWindow" mc:Ignorable="d" Title="Super PDF Converter" Height="307" Width="518" x:Name="myMainWindow" Icon="Images/favicon.png"> <Grid Name="MainGrid" SizeChanged="MainGrid_SizeChanged" VerticalAlignment="Center" HorizontalAlignment="Center" Height="307"> <Grid.LayoutTransform> <ScaleTransform x:Name="ApplicationScaleTransform" CenterX="0" CenterY="0" ScaleX="{Binding ElementName=myMainWindow, Path=ScaleValue}" ScaleY="{Binding ElementName=myMainWindow, Path=ScaleValue}" /> </Grid.LayoutTransform> </Grid> </Window>
Building our UI
Then let’s add our logo and the name of our app as a label.
<Window 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:PDFConverterSyncfusion" xmlns:syncfusion="<http://schemas.syncfusion.com/wpf>" x:Class="PDFConverterSyncfusion.MainWindow" x:Name="myMainWindow" mc:Ignorable="d" Icon="Images/favicon.png" Title="Super PDF Converter" Height="300" Width="500"> <Grid> <Grid.LayoutTransform> <ScaleTransform x:Name="ApplicationScaleTransform" CenterX="0" CenterY="0" ScaleX="{Binding ElementName=myMainWindow, Path=ScaleValue}" ScaleY="{Binding ElementName=myMainWindow, Path=ScaleValue}" /> </Grid.LayoutTransform> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"></ColumnDefinition> <ColumnDefinition Width="auto"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Image Grid.Column="1" Grid.Row="0" Source="Images/Logo.png" Stretch="Fill" HorizontalAlignment="Center" VerticalAlignment="Top" Height="72" Width="180" Margin="10,10,10,10" /> <Label Grid.Column="1" Grid.Row="1" Content="Super PDF Converter" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="16" Foreground="#FFEE256B" Height="auto" Width="auto" Margin="0,0,0,0" /> </Grid> </Window>
Then let’s add a button that we will use to open a file selection dialog, a text box to display the path of the selected path, and a dropdown menu to select what type of conversion we want.
But… We won’t use our regular buttons now, instead, we will use the following new UI components from syncfusion.
For this tutorial we will convert from PDF to Doc and vice versa as well as from PNG to PDF, you can add tons of conversions on your own later :).
Finally lets add the convert button itself!.
<Window 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:PDFConverterSyncfusion" xmlns:syncfusion="<http://schemas.syncfusion.com/wpf>" x:Class="PDFConverterSyncfusion.MainWindow" x:Name="myMainWindow" mc:Ignorable="d" Icon="Images/favicon.png" Title="Super PDF Converter" Height="300" Width="500"> <Grid> <Grid.LayoutTransform> <ScaleTransform x:Name="ApplicationScaleTransform" CenterX="0" CenterY="0" ScaleX="{Binding ElementName=myMainWindow, Path=ScaleValue}" ScaleY="{Binding ElementName=myMainWindow, Path=ScaleValue}" /> </Grid.LayoutTransform> <Grid.ColumnDefinitions> <ColumnDefinition Width="auto"></ColumnDefinition> <ColumnDefinition Width="auto"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition Height="auto"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Image Grid.Column="1" Grid.Row="0" Source="Images/Logo.png" Stretch="Fill" HorizontalAlignment="Center" VerticalAlignment="Top" Height="72" Width="180" Margin="10,10,10,10" /> <Label Grid.Column="1" Grid.Row="1" Content="Super PDF Converter" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" FontSize="16" Foreground="#FFEE256B" Height="auto" Width="auto" Margin="0,0,0,0" /> <syncfusion:ButtonAdv Content="Select File" SmallIcon="/Images/Select File Icon.png" HorizontalAlignment="Left" Height="35" Label="Select File" Margin="10,10,10,10" Grid.Row="2" VerticalAlignment="Center" Width="115" Background="#FFEF2F5A" Foreground="White" /> <TextBox x:Name="pathTextBox" Grid.Column="1" Grid.Row="2" TextWrapping="NoWrap" AcceptsReturn="False" Margin="10,10,10,10" /> <syncfusion:ComboBoxAdv x:Name="conversionDropDown" Grid.Column="2" Grid.Row="2" AllowMultiSelect="False" DefaultText="Select" Foreground="White" Background="#FFEF2F5A" Width="115" Margin="10,10,10,10" > <syncfusion:ComboBoxItemAdv Content=" Doc to PDF"/> <syncfusion:ComboBoxItemAdv Content=" PDF to Doc"/> <syncfusion:ComboBoxItemAdv Content=" PNG to PDF"/> </syncfusion:ComboBoxAdv> </Grid> </Window>
Our app should look like this..
Now back to our MainWindow.xaml.cs
First thing in our code behind let’s code the logic to resize our UI.
let’s add a new dependency property
//dependecy property called ScaleValue which is of type double and has two events in it's metadata, to adjust the scale public static readonly DependencyProperty ScaleValueProperty = DependencyProperty.Register("ScaleValue", typeof(double), typeof(MainWindow), new UIPropertyMetadata(1.0, new PropertyChangedCallback(OnScaleValueChanged), new CoerceValueCallback(OnCoerceScaleValue)));
Then let’s define these two events we added to our metadata.
private static object OnCoerceScaleValue(DependencyObject o, object value) { //set the mainWindow object MainWindow mainWindow = o as MainWindow; if (mainWindow != null) { //call the OnCoerceScaleValue and pass it the value we recieved as a double return mainWindow.OnCoerceScaleValue((double)value); } else { return value; } } private static void OnScaleValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { //set the mainWindow object MainWindow mainWindow = o as MainWindow; if (mainWindow != null) { //call the OnScaleValueChanged and pass it both the old value and the new value mainWindow.OnScaleValueChanged((double)e.OldValue, (double)e.NewValue); } }
Now let’s add the required methods we are calling from within our callback methods and also the size calculation logic
public double OnCoerceScaleValue(double value) { //for protection check if the double value is valid if (double.IsNaN(value)) { //if the double is not a number return 1 for the scale return 1.0f; } //we don't want to scale down our UI below 0.1 so we will get the max value between 0.1 and the current scale value = Math.Max(0.1, value); return value; } //since we need to actually add a call back for the OnScaleValueChanged, but we will be caclulating our scale //whenever we set or get our dependecy property public void OnScaleValueChanged(double oldValue, double newValue) { } //define the ScaleValue property, which corrsponds to our depedncy property name public double ScaleValue { get => (double)GetValue(ScaleValueProperty); set => SetValue(ScaleValueProperty, value); } //whenever we change the scale of our grid, call the CalculateScale method private void MainGrid_SizeChanged(object sender, EventArgs e) => CalculateScale(); private void CalculateScale() { //get our current height and width and divide it by our old height and width to get the new ratio double yScale = ActualHeight / 307; double xScale = ActualWidth / 518f; //our scaling should depend on the min between the width and height so our UI elements don't overlap double value = Math.Min(xScale, yScale); //set our ScaleValue (dependency property) ScaleValue = (double)OnCoerceScaleValue(myMainWindow, value); }
—test the resize logic—
Adding our Converting Logic
Now let’s code our button click events!.
Let’s code our Select File button event.
private void Button_Click(object sender, RoutedEventArgs e) { //Create file dialog and configure to open csv files only OpenFileDialog filelDialog = new OpenFileDialog(); // csvFielDialog.Filter = "CSF files(*.csv)|*.csv"; //Show the dialog to the user bool? result = filelDialog.ShowDialog(); //If the user selected something perform the actions with the file if (result.HasValue && result.Value) { //we will only set the file name and path to our pathTexBox pathTextBox.Text = filelDialog.FileName; } }
Once the conversion is done, we want to open the path of our converted file.
So let’s add a method for that!.
This method will only take the path of the file we want, and it will open it’s folder in the windows file explorer.
private void OpenFolder(string folderPath) { //create a new proccess info to start the explorer.exe which will open file explorer in windows ProcessStartInfo startInfo = new ProcessStartInfo() { //we want the folder path only without the file name //so we take a substring starting from 0 till the last index of \ Arguments = folderPath.Substring(0,folderPath.LastIndexOf('\\')), FileName = "explorer.exe", }; //start the proccess Process.Start(startInfo); }
Now we are ready to code our Convert Button Click event method.
It will be a switch statement to determine which type of conversion to use and for every conversion, we will create a method. We will need 3 void methods that take a string which is the file name itself.
private void Button_Click_1(object sender, RoutedEventArgs e) { //check if the textbox for the path is empty if (pathTextBox.Text == string.Empty) { //display an warning and exit the method MessageBox.Show("Please select a file"); return; } //switch over the selected conversion type, index of -1 means nothing is selected switch (conversionDropDown.SelectedIndex) { case 0://"Doc to PDF": ConvertDocToPDF(pathTextBox.Text); break; case 1:// "PDF to Doc": ConvertPDFtoDOC(pathTextBox.Text); break; case 2:// "PNG to DOC": ConvertPNGtoPDF(pathTextBox.Text); break; default: MessageBox.Show("Please select an option"); return; } //open the folder containing the converted file in file explorer OpenFolder(pathTextBox.Text); }
Now let’s create our conversion methods
ConvertPNGtoPDF
private void ConvertPNGtoPDF(string pngPath) { //Create an instance of pdf document PdfDocument pdfDoc = new PdfDocument(); //read the png image and itno a pdf image object PdfImage pdfImage = PdfImage.FromStream(new FileStream(pngPath, FileMode.Open)); //create a new pdfpage PdfPage pdfPage = new PdfPage(); //add a new section to our pdf //because a pdf file contains sections, and pdf sections contains pages which will contain our image PdfSection pdfSection = pdfDoc.Sections.Add(); //add the pdf page into the list of pages of our pdf section pdfSection.Pages.Insert(0, pdfPage); //draw the image into our pdf page pdfPage.Graphics.DrawImage(pdfImage, 0, 0); //Save the PDF file //the name of the new file will be the same name of the file before conversion but with the new file extension string newPNGPath = pngPath.Split('.')[0] + ".pdf"; pdfDoc.Save(newPNGPath); //Close the instance of document objects pdfDoc.Close(true); }
ConvertPDFToDoc
private void ConvertPDFtoDOC(string pdfPath) { //Creates a new Word document. WordDocument wordDocument = new WordDocument(); //Adds new section to the document. IWSection section = wordDocument.AddSection(); //Sets the page margins to zero. section.PageSetup.Margins.All = 0; //Adds new paragraph to the section. IWParagraph firstParagraph = section.AddParagraph(); //create a new SizeF struct to store the value of the page width and size SizeF defaultPageSize = new SizeF(wordDocument.LastSection.PageSetup.PageSize.Width, wordDocument.LastSection.PageSetup.PageSize.Height); //Loads the PDF document from the given file path. using (PdfLoadedDocument loadedDocument = new PdfLoadedDocument(pdfPath)) { //for every loded page in our document for (int i = 0; i < loadedDocument.Pages.Count; i++) { //Exports the PDF document page as image with the given size. using (var image = loadedDocument.ExportAsImage(i, defaultPageSize, false)) { //Adds image to the paragraph IWPicture picture = firstParagraph.AppendPicture(image); //Sets width and height for the image. picture.Width = image.Width; picture.Height = image.Height; } } }; //the name of the new file will be the same name of the file before conversion but with the new file extension string newPDFPath = pdfPath.Split('.')[0] + ".docx"; //Saves the Word document wordDocument.Save(newPDFPath); //Close the document. wordDocument.Dispose(); }
And Finally ConvertDocToPDF
private void ConvertDocToPDF(string docPath) { //create a new word document object using the document path WordDocument wordDocument = new WordDocument(docPath, FormatType.Automatic); //Create an instance of DocToPDFConverter DocToPDFConverter converter = new DocToPDFConverter(); //Convert Word document into PDF document PdfDocument pdfDocument = converter.ConvertToPDF(wordDocument); //Save the PDF file string newPDFPath = docPath.Split('.')[0] + ".pdf"; pdfDocument.Save(newPDFPath); //Close the instance of document objects pdfDocument.Close(true); wordDocument.Close(); }
now the last thing we want to do is to apply our theme.
In the constructor of our MainWindow before we call the InitalizeComponents method.
public MainWindow() { //create a new theme object FluentTheme fluentTheme = new FluentTheme() { //set the name of the theme ThemeName = "FluentLight", //set the hover and press effects (animation) HoverEffectMode = HoverEffect.None, PressedEffectMode = PressedEffect.Glow, //set the background to be acrylic transparent ShowAcrylicBackground = false }; //create a new theme settings FluentLightThemeSettings themeSettings = new FluentLightThemeSettings(); //set the font size to 16 and the font to barlow themeSettings.BodyFontSize = 16; themeSettings.FontFamily = new System.Windows.Media.FontFamily("Barlow"); //register the theme settings SfSkinManager.RegisterThemeSettings("FluentLight", themeSettings); //set the theme to the syncfusion skin manager, this refers to this window SfSkinManager.SetTheme(this, fluentTheme); //Note: it is important to initalize our components after we have configured our theme InitializeComponent(); }
Resizing
private void myMainWindow_SizeChanged(object sender, SizeChangedEventArgs e) { { myMainWindow.Width = e.NewSize.Width; myMainWindow.Height = e.NewSize.Height; double xChange = 1, yChange = 1; if (e.PreviousSize.Width != 0) xChange = (e.NewSize.Width / e.PreviousSize.Width); if (e.PreviousSize.Height != 0) yChange = (e.NewSize.Height / e.PreviousSize.Height); foreach (FrameworkElement fe in myGrid.Children) { if (fe is Grid == false) { fe.Height = fe.ActualHeight * yChange; fe.Width = fe.ActualWidth * xChange; Canvas.SetTop(fe, Canvas.GetTop(fe) * yChange); Canvas.SetLeft(fe, Canvas.GetLeft(fe) * xChange); } } } }
Test the app :)..
I hope you enjoyed this tutorial and learned something.
You can download the sourcecode from Github
https://github.com/tutorialseu/WPF-PDF-Converter-with-Syncfusion
or watch this tutorial on YouTube.