Test in production without watermarks.
Works wherever you need it to.
Get 30 days of fully functional product.
Have it up and running in minutes.
Full access to our support engineering team during your product trial
Generating PDFs with IronPDF is a common task for .NET developers—especially when building dynamic reports, invoices, or document automation systems. But if you’ve ever triggered PDF generation on the main UI thread in a Windows Forms or WPF app, you’ve likely seen your user interface freeze or become unresponsive. This is especially true when rendering large HTML content or processing complex PDF layouts.
That’s where the C# BackgroundWorker class comes in. This article walks through how to integrate IronPDF with BackgroundWorker to handle asynchronous operations in a desktop app without locking up the UI.
When you run CPU-heavy or IO-bound tasks like PDF generation on the main thread, it locks up the UI. Users can’t click, drag, or interact with the application while it’s busy. By using a BackgroundWorker object, you can move the work to a separate thread, keeping your interface snappy and usable during background processing.
If your app involves exporting data, converting HTML to PDF, or rendering detailed reports—offloading that to a background worker makes your application more professional and performant.
Although modern apps often use async/await, many older projects still benefit from BackgroundWorker for its simplicity and design-time support in Visual Studio.
IronPDF is a powerful .NET library designed for generating, editing, and working with PDF documents in C#. It uses a headless Chromium browser under the hood, allowing developers to convert HTML, CSS, JavaScript, and even complex web pages into accurate, print-quality PDFs. Unlike traditional PDF generators, IronPDF renders documents exactly as they would appear in a browser—matching layout, fonts, images, and styles pixel-for-pixel.
Key Features
IronPDF supports .NET Framework, .NET Core, and .NET 6/7+, making it ideal for both desktop and web-based .NET applications.
To get started, install IronPDF into your project using NuGet Package Manager:
Install-Package IronPdf
Install-Package IronPdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'Install-Package IronPdf
This will add all necessary references so you can begin using IronPDF’s ChromePdfRenderer, HtmlToPdf, and other powerful features.
For this example, we’ll use a Windows Forms application created with Visual Studio, with a button that triggers PDF generation and a label to indicate when the process is complete.
Now, we'll use the following code examples to break down the process of using BackgroundWorker in a structured and safe way:
You can create and configure a BackgroundWorker either in the designer or in code. Here’s the code approach:
private void SetupBackgroundWorker()
{
// new backgroundworker worker instance
worker = new BackgroundWorker(); // dowork event handler
worker.DoWork += PdfWorker_DoWork;
worker.RunWorkerCompleted += PdfWorker_RunWorkerCompleted; // final result handler
}
private void SetupBackgroundWorker()
{
// new backgroundworker worker instance
worker = new BackgroundWorker(); // dowork event handler
worker.DoWork += PdfWorker_DoWork;
worker.RunWorkerCompleted += PdfWorker_RunWorkerCompleted; // final result handler
}
Private Sub SetupBackgroundWorker()
' new backgroundworker worker instance
worker = New BackgroundWorker() ' dowork event handler
worker.DoWork += PdfWorker_DoWork
worker.RunWorkerCompleted += PdfWorker_RunWorkerCompleted ' final result handler
End Sub
This initializes the worker and wires up the necessary events for background execution and completion.
The DoWork method runs on a different thread, performing the background operation (generating the PDF):
private void PdfWorker_DoWork(object sender, DoWorkEventArgs e)
{
var Renderer = new ChromePdfRenderer();
// Simulate input from UI or parameters
string htmlContent = "<h1>Monthly Report</h1><p>Generated with IronPDF.</p>";
string outputPath = Path.Combine(Environment.CurrentDirectory, "Report.pdf");
// Generate PDF
var pdf = Renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs(outputPath);
// Optionally pass result info
e.Result = outputPath; // pass value to RunWorkerCompleted
}
private void PdfWorker_DoWork(object sender, DoWorkEventArgs e)
{
var Renderer = new ChromePdfRenderer();
// Simulate input from UI or parameters
string htmlContent = "<h1>Monthly Report</h1><p>Generated with IronPDF.</p>";
string outputPath = Path.Combine(Environment.CurrentDirectory, "Report.pdf");
// Generate PDF
var pdf = Renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs(outputPath);
// Optionally pass result info
e.Result = outputPath; // pass value to RunWorkerCompleted
}
Private Sub PdfWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim Renderer = New ChromePdfRenderer()
' Simulate input from UI or parameters
Dim htmlContent As String = "<h1>Monthly Report</h1><p>Generated with IronPDF.</p>"
Dim outputPath As String = Path.Combine(Environment.CurrentDirectory, "Report.pdf")
' Generate PDF
Dim pdf = Renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs(outputPath)
' Optionally pass result info
e.Result = outputPath ' pass value to RunWorkerCompleted
End Sub
Note: You cannot interact with UI controls here since it runs on a worker thread.
Once the background thread completes, you can safely update the UI with the results.
private void PdfWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("Error: " + e.Error.Message);
}
else
{
string savedPath = e.Result.ToString();
MessageBox.Show("PDF created at:\n" + savedPath);
}
}
private void PdfWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("Error: " + e.Error.Message);
}
else
{
string savedPath = e.Result.ToString();
MessageBox.Show("PDF created at:\n" + savedPath);
}
}
Imports Microsoft.VisualBasic
Private Sub PdfWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
If e.Error IsNot Nothing Then
MessageBox.Show("Error: " & e.Error.Message)
Else
Dim savedPath As String = e.Result.ToString()
MessageBox.Show("PDF created at:" & vbLf & savedPath)
End If
End Sub
Add a Start button to execute the background task when clicked:
private void btnGeneratePDF_Click(object sender, EventArgs e)
{
if (pdfWorker == null)
SetupBackgroundWorker();
if (!pdfWorker.IsBusy)
{
btnGeneratePDF.Enabled = false;
pdfWorker.RunWorkerAsync(); // execute method in background
}
}
private void btnGeneratePDF_Click(object sender, EventArgs e)
{
if (pdfWorker == null)
SetupBackgroundWorker();
if (!pdfWorker.IsBusy)
{
btnGeneratePDF.Enabled = false;
pdfWorker.RunWorkerAsync(); // execute method in background
}
}
Private Sub btnGeneratePDF_Click(ByVal sender As Object, ByVal e As EventArgs)
If pdfWorker Is Nothing Then
SetupBackgroundWorker()
End If
If Not pdfWorker.IsBusy Then
btnGeneratePDF.Enabled = False
pdfWorker.RunWorkerAsync() ' execute method in background
End If
End Sub
Here’s everything tied together in a single working Windows Forms snippet:
using System;
using System.ComponentModel;
using IronPdf;
using System.IO;
using System.Windows.Forms;
namespace TestApp
{
public partial class Form1 : Form
{
private BackgroundWorker worker;
public Form1()
{
InitializeComponent();
SetupBackgroundWorker(); }
private void SetupBackgroundWorker()
{
worker = new BackgroundWorker();
worker.DoWork += PdfWorker_DoWork;
worker.RunWorkerCompleted += PdfWorker_RunWorkerCompleted;
}
private void btnGeneratePDF_Click(object sender, EventArgs e)
{
if (!worker.IsBusy)
{
btnGeneratePDF.Enabled = false;
worker.RunWorkerAsync();
}
}
private void PdfWorker_DoWork(object sender, DoWorkEventArgs e)
{
var Renderer = new ChromePdfRenderer();
string htmlContent = "<h1>Report</h1><p>This PDF was generated in the background.</p>";
string outputPath = Path.Combine(Environment.CurrentDirectory, "Report.pdf");
var pdf = Renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs(outputPath);
e.Result = outputPath;
}
private void PdfWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnGeneratePDF.Enabled = true;
if (e.Error != null)
{
MessageBox.Show("Failed: " + e.Error.Message);
}
else
{
MessageBox.Show("PDF created: " + e.Result.ToString());
}
}
private void btnGeneratePDF_Click_1(object sender, EventArgs e)
{
if (!worker.IsBusy)
{
btnGeneratePDF.Enabled = false;
worker.RunWorkerAsync();
}
}
}
}
using System;
using System.ComponentModel;
using IronPdf;
using System.IO;
using System.Windows.Forms;
namespace TestApp
{
public partial class Form1 : Form
{
private BackgroundWorker worker;
public Form1()
{
InitializeComponent();
SetupBackgroundWorker(); }
private void SetupBackgroundWorker()
{
worker = new BackgroundWorker();
worker.DoWork += PdfWorker_DoWork;
worker.RunWorkerCompleted += PdfWorker_RunWorkerCompleted;
}
private void btnGeneratePDF_Click(object sender, EventArgs e)
{
if (!worker.IsBusy)
{
btnGeneratePDF.Enabled = false;
worker.RunWorkerAsync();
}
}
private void PdfWorker_DoWork(object sender, DoWorkEventArgs e)
{
var Renderer = new ChromePdfRenderer();
string htmlContent = "<h1>Report</h1><p>This PDF was generated in the background.</p>";
string outputPath = Path.Combine(Environment.CurrentDirectory, "Report.pdf");
var pdf = Renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs(outputPath);
e.Result = outputPath;
}
private void PdfWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnGeneratePDF.Enabled = true;
if (e.Error != null)
{
MessageBox.Show("Failed: " + e.Error.Message);
}
else
{
MessageBox.Show("PDF created: " + e.Result.ToString());
}
}
private void btnGeneratePDF_Click_1(object sender, EventArgs e)
{
if (!worker.IsBusy)
{
btnGeneratePDF.Enabled = false;
worker.RunWorkerAsync();
}
}
}
}
Imports System
Imports System.ComponentModel
Imports IronPdf
Imports System.IO
Imports System.Windows.Forms
Namespace TestApp
Partial Public Class Form1
Inherits Form
Private worker As BackgroundWorker
Public Sub New()
InitializeComponent()
SetupBackgroundWorker()
End Sub
Private Sub SetupBackgroundWorker()
worker = New BackgroundWorker()
AddHandler worker.DoWork, AddressOf PdfWorker_DoWork
AddHandler worker.RunWorkerCompleted, AddressOf PdfWorker_RunWorkerCompleted
End Sub
Private Sub btnGeneratePDF_Click(ByVal sender As Object, ByVal e As EventArgs)
If Not worker.IsBusy Then
btnGeneratePDF.Enabled = False
worker.RunWorkerAsync()
End If
End Sub
Private Sub PdfWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim Renderer = New ChromePdfRenderer()
Dim htmlContent As String = "<h1>Report</h1><p>This PDF was generated in the background.</p>"
Dim outputPath As String = Path.Combine(Environment.CurrentDirectory, "Report.pdf")
Dim pdf = Renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs(outputPath)
e.Result = outputPath
End Sub
Private Sub PdfWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
btnGeneratePDF.Enabled = True
If e.Error IsNot Nothing Then
MessageBox.Show("Failed: " & e.Error.Message)
Else
MessageBox.Show("PDF created: " & e.Result.ToString())
End If
End Sub
Private Sub btnGeneratePDF_Click_1(ByVal sender As Object, ByVal e As EventArgs)
If Not worker.IsBusy Then
btnGeneratePDF.Enabled = False
worker.RunWorkerAsync()
End If
End Sub
End Class
End Namespace
Form output
PDF Output
The DoWork event handler runs on a different thread, so you can’t access UI elements directly. Use RunWorkerCompleted or control Invoke() calls for safe UI updates.
If your task is long, enable WorkerSupportsCancellation = true and monitor CancellationPending inside DoWork to support requested cancellation.
You can enable WorkerReportsProgress = true and use the ProgressChanged event to show a progress bar or messages.
When using RunWorkerAsync(argument), validate the argument in DoWork and return any method results through e.Result.
Using BackgroundWorker with IronPDF enables you to perform heavy PDF rendering tasks on a background thread, keeping your application responsive. This is especially valuable when working with WinForms or WPF apps that require responsive UI updates during long-running tasks like PDF generation.
By handling the dowork event handler, monitoring the final result, and safely updating your user interface in the runworkercompleted event, you ensure your background operations run smoothly.
While async/await is often the go-to for new applications, BackgroundWorker remains a reliable tool for legacy or WinForms projects. Whether you're exporting reports or generating documents on-the-fly, this approach will help you get the most out of IronPDF while keeping your app smooth and user-friendly.
Ready to try it yourself?
Download the free IronPDF trial and start building powerful PDF solutions in C# today. The trial gives you full access to the features showcased in this article—no credit card required.
The main benefit of using the C# BackgroundWorker class with IronPDF is to handle asynchronous operations in a desktop app without locking up the UI, ensuring that the user interface remains responsive during long-running tasks like PDF generation.
Keeping the UI responsive is important because it allows users to interact with the application smoothly, without experiencing freezes or unresponsiveness, especially during CPU-heavy or IO-bound tasks like PDF generation.
IronPDF uses a headless Chromium browser to convert HTML, CSS, JavaScript, and complex web pages into accurate, print-quality PDFs, rendering documents exactly as they would appear in a browser.
No, it is not possible to interact with UI controls in the DoWork method because it runs on a separate thread. UI updates should be handled in the RunWorkerCompleted event or by using control Invoke() calls.
IronPDF offers features such as HTML to PDF conversion, image and text rendering, merging and splitting PDFs, and working with interactive PDF forms, all without needing Adobe Acrobat or Microsoft Office installed.
You can install IronPDF in your project using the NuGet Package Manager with the command: Install-Package IronPdf.
Some best practices include avoiding UI access in the DoWork event handler, supporting asynchronous cancellation, using progress updates if necessary, and validating input arguments when using RunWorkerAsync.
While BackgroundWorker is compatible with legacy WinForms apps, modern applications typically use async/await for asynchronous operations. BackgroundWorker is still useful for its simplicity and design-time support in older projects.
The RunWorkerCompleted event is used to safely update the UI with the results of the background operation once it completes, allowing you to handle any errors and display the outcome to the user.
The full code example demonstrates how to set up and use a BackgroundWorker in a Windows Forms application to generate PDFs with IronPDF, including setting up event handlers for DoWork and RunWorkerCompleted, and triggering the background task from the UI.