How to print Excel documents in Xamarin using XlsIO
Syncfusion® Excel library (XlsIO) is a .NET Excel library used to create, read, and edit Excel documents. It also converts Excel documents to PDF files and prints Excel documents.
This article explains how to print Excel documents in Xamarin.Forms:
- Portable
- Android
- iOS
- UWP
Initially, the Excel documents must be converted to PDF file streams, and then the converted PDF streams will be printed using native printing functionalities available on the respective platforms using DependencyService of Xamarin.Forms. These platform-specific printing options can be used by defining an interface in the portable project and implementing the same in the platform projects using the specific code.
The following code snippets illustrate how to print Excel documents in the Xamarin.Forms platform.
Portable
Define the following interface.
C#
namespace ExcelPrintingSample { public interface IPrintService { void Print(Stream inputStream, string fileName); } }
Steps to print the Excel Document
1)To print the Excel document in Xamarin, the Excel document need to be converted to a PDF document. To convert the Excel document to a PDF file, the following Syncfusion NuGets has to be installed in the application.
2)In the button click event, open the Excel document using XlsIO and convert the Excel document to PDF using XlsIORenderer. This PDF document stream will be sent to the DependencyService for printing.
C#
private void PrintBtn_Clicked(object sender, EventArgs e) { ExcelEngine excelEngine = new ExcelEngine(); IApplication application = excelEngine.Excel; Stream stream = typeof(App).GetType().Assembly.GetManifestResourceStream("ExcelPrintingSample.Sample.xlsx"); IWorkbook workbook = application.Workbooks.Open(stream); XlsIORenderer renderer = new XlsIORenderer(); XlsIORendererSettings settings = new XlsIORendererSettings(); settings.IsConvertBlankPage = false; // Embed the fonts in the output document settings.EmbedFonts = true; // Set the Layout Options for the output Pdf page. settings.LayoutOptions = Syncfusion.XlsIORenderer.LayoutOptions.FitSheetOnOnePage; PdfDocument pdfDocument = renderer.ConvertToPDF(workbook, settings); MemoryStream memoryStream = new MemoryStream(); pdfDocument.Save(memoryStream); pdfDocument.Close(true); DependencyService.Get<IPrintService>().Print(memoryStream, "output.pdf"); }
1) Android devices with the version 5.1.1 or below, might have not preview the document properly due to missing required fonts in the devices. So setting XlsIORendererSettings.EmbedFonts to true to preview the document properly.
2) Refer the Excel to PDF conversion UG documentation for further information.
Implement the interface in the platform projects with the available platform specific printing options.
Android
C#
// Register the Android implementation of the interface with DependencyService [assembly: Dependency(typeof(PrintService))] namespace ExcelPrintingSample.Droid { class PrintService : IPrintService { public void Print(Stream inputStream, string fileName) { if (inputStream.CanSeek) // Reset the position of PDF document stream to be printed inputStream.Position = 0; // Create a new file in the Personal folder with the given name string createdFilePath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), fileName); // Save the stream to the created file using (var dest = System.IO.File.OpenWrite(createdFilePath)) inputStream.CopyTo(dest); string filePath = createdFilePath; PrintManager printManager = (PrintManager)Forms.Context.GetSystemService(Context.PrintService); PrintDocumentAdapter pda = new CustomPrintDocumentAdapter(filePath); // Print with null PrintAttributes printManager.Print(fileName, pda, null); } } }
Define a class derived from the PrintDocumentAdapter and write the contents of the input file to the print destination in the OnWrite method.
C#
namespace ExcelPrintingSample.Droid { internal class CustomPrintDocumentAdapter : PrintDocumentAdapter { internal string FileToPrint { get; set; } internal CustomPrintDocumentAdapter(string fileDesc) { FileToPrint = fileDesc; } public override void OnLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { if (cancellationSignal.IsCanceled) { callback.OnLayoutCancelled(); return; } PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(FileToPrint).SetContentType(Android.Print.PrintContentType.Document).Build(); callback.OnLayoutFinished(pdi, true); } public override void OnWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) { InputStream input = null; OutputStream output = null; try { // Create FileInputStream object from the given file input = new FileInputStream(FileToPrint); // Create FileOutputStream object from the destination FileDescriptor instance output = new FileOutputStream(destination.FileDescriptor); byte[] buf = new byte[1024]; int bytesRead; while ((bytesRead = input.Read(buf)) > 0) { // Write the contents of the given file to the print destination output.Write(buf, 0, bytesRead); } callback.OnWriteFinished(new PageRange[] { PageRange.AllPages }); } catch (FileNotFoundException ee) { // Catch exception } catch (Exception e) { // Catch exception } finally { try { input.Close(); output.Close(); } catch (IOException e) { e.PrintStackTrace(); } } } } }
iOS
C#
// Register the iOS implementation of the interface with DependencyService [assembly: Dependency(typeof(PrintService))] namespace ExcelPrintingSample.iOS { class PrintService : IPrintService { public void Print(Stream inputStream, string fileName) { var printInfo = UIPrintInfo.PrintInfo; printInfo.OutputType = UIPrintInfoOutputType.General; printInfo.JobName = "Print PDF Sample"; // Get the path of the MyDocuments folder var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // Get the path of the Library folder within the MyDocuments folder var library = Path.Combine(documents, "..", "Library"); // Create a new file with the input file name in the Library folder var m_filepath = Path.Combine(library, fileName); // Write the contents of the input file to the newly created file using (MemoryStream tempStream = new MemoryStream()) { inputStream.Position = 0; inputStream.CopyTo(tempStream); File.WriteAllBytes(m_filepath, tempStream.ToArray()); } var printer = UIPrintInteractionController.SharedPrintController; printInfo.OutputType = UIPrintInfoOutputType.General; printer.PrintingItem = NSUrl.FromFilename(m_filepath); printer.PrintInfo = printInfo; printer.ShowsPageRange = true; printer.Present(true, (handler, completed, err) => { if (!completed && err != null) { Console.WriteLine("error"); } }); } } }
UWP
C#
// Register the UWP implementation of the interface with DependencyService [assembly: Xamarin.Forms.Dependency(typeof(PrintService))] namespace ExcelPrintingSample.UWP { class PrintService : IPrintService { internal int m_pageCount; internal global::Windows.Data.Pdf.PdfDocument _pdfDocument; private PrintDocument printDocument; private IPrintDocumentSource printDocumentSource; string m_fileName; internal Dictionary<int, UIElement> printPreviewPages = new Dictionary<int, UIElement>(); private List<string> m_imagePaths = new List<string>(); IRandomAccessStream randomStream; public async void Print(Stream inputStream, string fileName) { inputStream.Position = 0; MemoryStream ms = new MemoryStream(); // Copy the input stream to a new MemoryStream inputStream.CopyTo(ms); ms.Position = 0; // Convert the MemoryStream to a stream that allows random access randomStream = await ConvertToRandomAccessStream(ms); IAsyncOperation<global::Windows.Data.Pdf.PdfDocument> result = null; // Create the IAsyncOperation object from the given random stream result = global::Windows.Data.Pdf.PdfDocument.LoadFromStreamAsync(randomStream); result.AsTask().Wait(); // Get the PdfDocument instance that represents the PDF document that is loaded _pdfDocument = result.GetResults(); result = null; m_pageCount = (int)_pdfDocument.PageCount; m_fileName = fileName; try { UIDispatcher.Execute(async () => { RegisterForPrint(); //Show the UI window with printing options await PrintManager.ShowPrintUIAsync(); }); } catch { UIDispatcher.Execute(async () => { RegisterForPrint(); // Show the UI window with printing options PrintManager.ShowPrintUIAsync(); }); } } // Method to convert the given MemoryStream to a stream that allows random access. public async Task<IRandomAccessStream> ConvertToRandomAccessStream(MemoryStream memoryStream) { var randomAccessStream = new InMemoryRandomAccessStream(); MemoryStream contentStream = new MemoryStream(); memoryStream.CopyTo(contentStream); using (var outputStream = randomAccessStream.GetOutputStreamAt(0)) { using (var dw = new DataWriter(outputStream)) { var task = new Task(() => dw.WriteBytes(contentStream.ToArray())); task.Start(); await task; await dw.StoreAsync(); await outputStream.FlushAsync(); await dw.FlushAsync(); outputStream.Dispose(); dw.DetachStream(); dw.Dispose(); } } return randomAccessStream; } PrintManager printMan; private void RegisterForPrint() { printDocument = new PrintDocument(); // Save the DocumentSource. printDocumentSource = printDocument.DocumentSource; // Add an event handler which provides all final print pages. printDocument.AddPages += AddPrintPages; // Create a PrintManager and add a handler for printing initialization. printMan = PrintManager.GetForCurrentView(); printMan.PrintTaskRequested += PrintTaskRequested; } Image imageCtrl = new Image(); private async void AddPrintPages(object sender, AddPagesEventArgs e) { try { await PrepareForPrint(0, m_pageCount); PrintDocument printDoc = (PrintDocument)sender; printDoc.AddPagesComplete(); } catch { PrintDocument printDoc = (PrintDocument)sender; printDoc.InvalidatePreview(); } } private async Task<int> PrepareForPrint(int startIndex, int count) { StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder; int result = await PrepareForPrint(startIndex, count, tempFolder); tempFolder = null; return result; } private async Task<int> PrepareForPrint(int p, int count, StorageFolder tempfolder) { for (int i = p; i < count; i++) { float zoomfactor = 1; // Adjust the zoom factor according to the display properties double customZoomFactor = zoomfactor * 96 / DisplayProperties.LogicalDpi; ApplicationLanguages.PrimaryLanguageOverride = CultureInfo.InvariantCulture.TwoLetterISOLanguageName; // Get the page from the PDF document with a given index var pdfPage = _pdfDocument.GetPage(uint.Parse(i.ToString())); double pdfPagePreferredZoom = pdfPage.PreferredZoom /** m_pdfViewer.PrinterSettings.QualityFactor*/; IRandomAccessStream randomStream = new InMemoryRandomAccessStream(); global::Windows.Data.Pdf.PdfPageRenderOptions pdfPageRenderOptions = new global::Windows.Data.Pdf.PdfPageRenderOptions(); Size pdfPageSize = pdfPage.Size; // Set the height to which the page is to be printed pdfPageRenderOptions.DestinationHeight = (uint)(pdfPageSize.Height * pdfPagePreferredZoom); // Set the width to which the page is to be printed pdfPageRenderOptions.DestinationWidth = (uint)(pdfPageSize.Width * pdfPagePreferredZoom); await pdfPage.RenderToStreamAsync(randomStream, pdfPageRenderOptions); // Create a new Image to which the page will be rendered imageCtrl = new Image(); BitmapImage src = new BitmapImage(); randomStream.Seek(0); // Obtain image source from the randomstream src.SetSource(randomStream); // set the image source to the image imageCtrl.Source = src; var DisplayInformation = Windows.Graphics.Display.DisplayInformation.GetForCurrentView(); var dpi = DisplayInformation.LogicalDpi/96; imageCtrl.Height = src.PixelHeight/dpi; imageCtrl.Width = src.PixelWidth/dpi; randomStream.Dispose(); pdfPage.Dispose(); printDocument.AddPage(imageCtrl); } return 0; } PrintTask printTask; MessageDialog msgDialog; private async void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e) { printTask = e.Request.CreatePrintTask(m_fileName, sourceRequested => sourceRequested.SetSource(printDocumentSource)); printTask.Completed += printTask_Completed; } // Called when the printing operation completes private void printTask_Completed(PrintTask sender, PrintTaskCompletedEventArgs args) { printTask.Completed -= printTask_Completed; printMan.PrintTaskRequested -= PrintTaskRequested; UIDispatcher.Execute(async () => { msgDialog = new MessageDialog("Printing operation has been completed"); await msgDialog.ShowAsync(); }); // PrintManager printMan = PrintManager.GetForCurrentView(); // printMan.PrintTaskRequested -= PrintTaskRequested; } } // Helper class to run operations async internal class UIDispatcher { private static CoreDispatcher Dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher; /// <summary> /// Executes the action using UIElement. /// </summary> /// <param name="action">An Action.</param> internal static void Execute(Action action) { if (CoreApplication.MainView.CoreWindow == null || Dispatcher.HasThreadAccess) action(); else Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => action()).AsTask().Wait(); } } }
Sample link:
You can download the complete example to print Excel documents in Xamarin.Forms from print-excel-files-in-xamarin.zip
Refer here to explore the rich set of Syncfusion® Excel library (XlsIO) features.
Note:
Starting with v16.2.0.x, if you reference Syncfusion® assemblies from a trial setup or from the NuGet feed, include a license key in your projects. Refer to the link to learn about generating and registering the Syncfusion® license key in your application to use the components without a trial message.
Conclusion
I hope you enjoyed learning about How to print Excel documents in Xamarin using XlsIO.
You can refer to our XIsIO’s feature tour page to learn about its other groundbreaking features. Explore our UG documentation and online demos to understand how to manipulate data in Excel documents.
If you are an existing user, you can access our latest components from the License and Downloads page. For new users, you can try our 30-day free trial to check out XlsIO and other Syncfusion® components.
If you have any queries or require clarification, please let us know in the comments below or contact us through our support forums, Support Tickets, or feedback portal. We are always happy to assist you!