How to Create a Desktop Barcode Application (Scanner/Generator) with .NET MAUI

For a comprehensive software solution, it is not just about mobile accessibility. The ability to deploy natively on desktop operating systems, such as Windows and macOS, is just as critical. This cross-platform approach enables businesses to leverage the full power of workstations for high-volume tasks such as asset tracking and administration.

Without proper desktop support, workflows are interrupted or, worse, forced onto less capable devices. This is particularly important in inventory management, where office staff need to generate batches of codes or verify scans rapidly without leaving their desks.

IronBarcode delivers the necessary tools to implement these features, ensuring your .NET MAUI application performs reliably on any computer.

In this article, we'll explain how to integrate IronBarcode to build both a Desktop Barcode Scanner and a Desktop Barcode Generator.

Get started with IronBarcode



.NET MAUI Desktop Application

Integrating IronBarcode into a .NET MAUI app is straightforward, as the library works natively with the desktop platform out of the box. In this example, we'll create both a barcode scanner and a barcode generator using IronBarcode separately.

Let's start with the barcode scanner first.

Barcode Scanner Interface XAML

For the .NET MAUI interface, a simple interface is implemented to allow users to upload barcode images via a submit button. The MainPage.xaml file within the project should be replaced with the contents shown below.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">

    <ScrollView>
        <VerticalStackLayout Spacing="25" Padding="30" VerticalOptions="Center">

            <Label Text="Desktop Barcode Scanner"
                   FontSize="32"
                   HorizontalOptions="Center" />

            <Image x:Name="ScannerImage"
                   HeightRequest="300"
                   WidthRequest="400"
                   BackgroundColor="#F0F0F0"
                   Aspect="AspectFit"
                   HorizontalOptions="Center" />

            <Button Text="Select Image to Scan"
                    Clicked="OnScanButtonClicked"
                    HorizontalOptions="Center" 
                    WidthRequest="200"/>

            <Label x:Name="ResultLabel"
                   Text="Result will appear here..."
                   FontSize="20"
                   HorizontalOptions="Center"
                   HorizontalTextAlignment="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">

    <ScrollView>
        <VerticalStackLayout Spacing="25" Padding="30" VerticalOptions="Center">

            <Label Text="Desktop Barcode Scanner"
                   FontSize="32"
                   HorizontalOptions="Center" />

            <Image x:Name="ScannerImage"
                   HeightRequest="300"
                   WidthRequest="400"
                   BackgroundColor="#F0F0F0"
                   Aspect="AspectFit"
                   HorizontalOptions="Center" />

            <Button Text="Select Image to Scan"
                    Clicked="OnScanButtonClicked"
                    HorizontalOptions="Center" 
                    WidthRequest="200"/>

            <Label x:Name="ResultLabel"
                   Text="Result will appear here..."
                   FontSize="20"
                   HorizontalOptions="Center"
                   HorizontalTextAlignment="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
XML

Desktop Barcode Scanner Logic CS

Next, the logic for when the user clicks on the button is implemented. An OnScanButtonClicked event handler is attached to the scan button in the UI.

PickPhotoAsync is first used to let users choose the barcode to upload, followed by OpenReadAsync to access the file stream. The image data is immediately copied into a MemoryStream using CopyToAsync. This allows the data to be used simultaneously to display the image on screen and for the Read method to scan the barcode.

Finally, the barcode value is displayed in the UI if a valid barcode is detected, or a red message is displayed stating that no barcode was found in the image.

Please note Replace the license key with your own before testing the application.

using IronBarCode;

namespace MauiApp1
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            // Your license key is set here
            IronBarCode.License.LicenseKey = "YOUR_KEY"
        }

        private async void OnScanButtonClicked(object sender, EventArgs e)
        {
            try
            {
                var fileResult = await MediaPicker.Default.PickPhotoAsync();

                if (fileResult != null)
                {
                    // 1. Copy the file content into a byte array or MemoryStream immediately
                    // This ensures we have the data in memory before the file closes
                    byte[] imageBytes;
                    using (var stream = await fileResult.OpenReadAsync())
                    using (var memoryStream = new MemoryStream())
                    {
                        await stream.CopyToAsync(memoryStream);
                        imageBytes = memoryStream.ToArray();
                    }

                    // 2. Set the Image Source for the UI
                    // We give the UI a FRESH stream from the bytes we just saved
                    ScannerImage.Source = ImageSource.FromStream(() => new MemoryStream(imageBytes));

                    // 3. Process the Barcode
                    // We give IronBarcode its OWN fresh stream from the same bytes
                    using (var processingStream = new MemoryStream(imageBytes))
                    {
                        // 4. Read the barcode with Read
                        var results = BarcodeReader.Read(processingStream);

                        // 5. Display barcode results
                        if (results != null && results.Count > 0)
                        {

                            // Successfully found barcode value
                            ResultLabel.Text = $"Success: {results[0].Value}";
                            ResultLabel.TextColor = Colors.Green;
                        }
                        else
                        {
                            // Image uploaded has no barcode or barcode value is not found
                            ResultLabel.Text = "No barcode detected.";
                            ResultLabel.TextColor = Colors.Red;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // Display any exception thrown in runtime
                ResultLabel.Text = $"Error: {ex.Message}";
                ResultLabel.TextColor = Colors.Red;
            }
        }
    }
}
using IronBarCode;

namespace MauiApp1
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            // Your license key is set here
            IronBarCode.License.LicenseKey = "YOUR_KEY"
        }

        private async void OnScanButtonClicked(object sender, EventArgs e)
        {
            try
            {
                var fileResult = await MediaPicker.Default.PickPhotoAsync();

                if (fileResult != null)
                {
                    // 1. Copy the file content into a byte array or MemoryStream immediately
                    // This ensures we have the data in memory before the file closes
                    byte[] imageBytes;
                    using (var stream = await fileResult.OpenReadAsync())
                    using (var memoryStream = new MemoryStream())
                    {
                        await stream.CopyToAsync(memoryStream);
                        imageBytes = memoryStream.ToArray();
                    }

                    // 2. Set the Image Source for the UI
                    // We give the UI a FRESH stream from the bytes we just saved
                    ScannerImage.Source = ImageSource.FromStream(() => new MemoryStream(imageBytes));

                    // 3. Process the Barcode
                    // We give IronBarcode its OWN fresh stream from the same bytes
                    using (var processingStream = new MemoryStream(imageBytes))
                    {
                        // 4. Read the barcode with Read
                        var results = BarcodeReader.Read(processingStream);

                        // 5. Display barcode results
                        if (results != null && results.Count > 0)
                        {

                            // Successfully found barcode value
                            ResultLabel.Text = $"Success: {results[0].Value}";
                            ResultLabel.TextColor = Colors.Green;
                        }
                        else
                        {
                            // Image uploaded has no barcode or barcode value is not found
                            ResultLabel.Text = "No barcode detected.";
                            ResultLabel.TextColor = Colors.Red;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // Display any exception thrown in runtime
                ResultLabel.Text = $"Error: {ex.Message}";
                ResultLabel.TextColor = Colors.Red;
            }
        }
    }
}
$vbLabelText   $csharpLabel

Output with Barcode Value found

Barcodes found output

As you can see, the application displays the barcode result and the uploaded barcode image.

Output with no Barcode Value found

No Barcodes found output

As you can see, when a user uploads an image that doesn't contain a barcode, it displays a red message stating "No barcodes found."

Desktop Barcode Generator

The next part builds on the same concept by integrating IronBarcode into MAUI to create a barcode generator.

Barcode Generator Interface XAML

For the generator's interface, a simple form is implemented to allow text entry and barcode type selection via a dropdown menu. A button is included to trigger the generation and saving process, along with an image view to display the result. The MainPage.xaml file should be replaced with the contents shown below.

Please refer here for the complete list of 1D barcodes and here for 2D barcodes.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">

    <ScrollView>
        <VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">

            <Label Text="Barcode Generator"
                   FontSize="32"
                   HorizontalOptions="Center" />

            <Entry x:Name="BarcodeEntry"
                   Placeholder="Enter value (e.g. 12345 or https://ironsoftware.com)"
                   WidthRequest="300" />

            <Picker x:Name="BarcodeTypePicker"
                    Title="Select Barcode Type"
                    WidthRequest="300">
                <Picker.ItemsSource>
                    <x:Array Type="{x:Type x:String}">
                        <x:String>QRCode</x:String>
                        <x:String>Code128</x:String>
                        <x:String>EAN13</x:String>
                        <x:String>Code39</x:String>
                        <x:String>PDF417</x:String>
                    </x:Array>
                </Picker.ItemsSource>
            </Picker>

            <Button Text="Generate &amp; Save"
                    Clicked="OnGenerateButtonClicked"
                    HorizontalOptions="Center"
                    WidthRequest="200" />

            <Image x:Name="GeneratedImage"
                   HeightRequest="200"
                   WidthRequest="300"
                   BackgroundColor="#F0F0F0"
                   Aspect="AspectFit" />

            <Label x:Name="StatusLabel"
                   FontSize="16"
                   HorizontalOptions="Center"
                   HorizontalTextAlignment="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiApp1.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">

    <ScrollView>
        <VerticalStackLayout Spacing="20" Padding="30" VerticalOptions="Center">

            <Label Text="Barcode Generator"
                   FontSize="32"
                   HorizontalOptions="Center" />

            <Entry x:Name="BarcodeEntry"
                   Placeholder="Enter value (e.g. 12345 or https://ironsoftware.com)"
                   WidthRequest="300" />

            <Picker x:Name="BarcodeTypePicker"
                    Title="Select Barcode Type"
                    WidthRequest="300">
                <Picker.ItemsSource>
                    <x:Array Type="{x:Type x:String}">
                        <x:String>QRCode</x:String>
                        <x:String>Code128</x:String>
                        <x:String>EAN13</x:String>
                        <x:String>Code39</x:String>
                        <x:String>PDF417</x:String>
                    </x:Array>
                </Picker.ItemsSource>
            </Picker>

            <Button Text="Generate &amp; Save"
                    Clicked="OnGenerateButtonClicked"
                    HorizontalOptions="Center"
                    WidthRequest="200" />

            <Image x:Name="GeneratedImage"
                   HeightRequest="200"
                   WidthRequest="300"
                   BackgroundColor="#F0F0F0"
                   Aspect="AspectFit" />

            <Label x:Name="StatusLabel"
                   FontSize="16"
                   HorizontalOptions="Center"
                   HorizontalTextAlignment="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>
XML

Desktop Barcode Generator Logic CS

Next, the logic for the button click event is implemented. An OnGenerateButtonClicked event handler is attached to the generate button in the UI.

User input is validated to ensure text is present and a type is selected, after which the selection is mapped to the correct BarcodeEncoding. BarcodeWriter.CreateBarcode is used to generate the image, resize it, and convert it to JPEG binary data. The image is then displayed on screen using a MemoryStream.

Finally, the generated barcode file is saved directly to the user's Desktop using File.WriteAllBytes, and the status label is updated to confirm the save location.

Please note Replace the license key with your own before testing the application.

using IronBarCode;
using System.IO; // Required for saving files

namespace MauiApp1
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            IronBarCode.License.LicenseKey = "YOUR-KEY";

            // Set default selection
            BarcodeTypePicker.SelectedIndex = 0;
        }

        private void OnGenerateButtonClicked(object sender, EventArgs e)
        {
            try
            {
                // 1. Get and Validate Input
                string text = BarcodeEntry.Text;

                if (string.IsNullOrWhiteSpace(text))
                {
                    StatusLabel.Text = "Error: Please enter text.";
                    StatusLabel.TextColor = Colors.Red;
                    return;
                }

                if (BarcodeTypePicker.SelectedIndex == -1)
                {
                    StatusLabel.Text = "Error: Please select a type.";
                    StatusLabel.TextColor = Colors.Red;
                    return;
                }

                // 2. Determine Encoding Type
                string selectedType = BarcodeTypePicker.SelectedItem.ToString();
                BarcodeEncoding encoding = BarcodeEncoding.QRCode;

                switch (selectedType)
                {
                    case "QRCode": encoding = BarcodeEncoding.QRCode; break;
                    case "Code128": encoding = BarcodeEncoding.Code128; break;
                    case "EAN13": encoding = BarcodeEncoding.EAN13; break;
                    case "Code39": encoding = BarcodeEncoding.Code39; break;
                    case "PDF417": encoding = BarcodeEncoding.PDF417; break;
                }

                // 3. Generate Barcode
                var barcode = BarcodeWriter.CreateBarcode(text, encoding);
                barcode.ResizeTo(400, 200); // Optional resizing

                // 4. Convert to Bytes (JPEG)
                var bytes = barcode.ToJpegBinaryData();

                // 5. Update UI
                GeneratedImage.Source = ImageSource.FromStream(() => new MemoryStream(bytes));

                // 6. Save to Desktop automatically
                string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                string fileName = $"barcode_{DateTime.Now:yyyyMMdd_HHmmss}.jpg";
                string fullPath = Path.Combine(desktopPath, fileName);

                File.WriteAllBytes(fullPath, bytes);

                // 7. Show Success Message
                StatusLabel.Text = $"Saved to Desktop:\n{fileName}";
                StatusLabel.TextColor = Colors.Green;
            }
            catch (Exception ex)
            {
                StatusLabel.Text = $"Error: {ex.Message}";
                StatusLabel.TextColor = Colors.Red;
            }
        }
    }
}
using IronBarCode;
using System.IO; // Required for saving files

namespace MauiApp1
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            IronBarCode.License.LicenseKey = "YOUR-KEY";

            // Set default selection
            BarcodeTypePicker.SelectedIndex = 0;
        }

        private void OnGenerateButtonClicked(object sender, EventArgs e)
        {
            try
            {
                // 1. Get and Validate Input
                string text = BarcodeEntry.Text;

                if (string.IsNullOrWhiteSpace(text))
                {
                    StatusLabel.Text = "Error: Please enter text.";
                    StatusLabel.TextColor = Colors.Red;
                    return;
                }

                if (BarcodeTypePicker.SelectedIndex == -1)
                {
                    StatusLabel.Text = "Error: Please select a type.";
                    StatusLabel.TextColor = Colors.Red;
                    return;
                }

                // 2. Determine Encoding Type
                string selectedType = BarcodeTypePicker.SelectedItem.ToString();
                BarcodeEncoding encoding = BarcodeEncoding.QRCode;

                switch (selectedType)
                {
                    case "QRCode": encoding = BarcodeEncoding.QRCode; break;
                    case "Code128": encoding = BarcodeEncoding.Code128; break;
                    case "EAN13": encoding = BarcodeEncoding.EAN13; break;
                    case "Code39": encoding = BarcodeEncoding.Code39; break;
                    case "PDF417": encoding = BarcodeEncoding.PDF417; break;
                }

                // 3. Generate Barcode
                var barcode = BarcodeWriter.CreateBarcode(text, encoding);
                barcode.ResizeTo(400, 200); // Optional resizing

                // 4. Convert to Bytes (JPEG)
                var bytes = barcode.ToJpegBinaryData();

                // 5. Update UI
                GeneratedImage.Source = ImageSource.FromStream(() => new MemoryStream(bytes));

                // 6. Save to Desktop automatically
                string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                string fileName = $"barcode_{DateTime.Now:yyyyMMdd_HHmmss}.jpg";
                string fullPath = Path.Combine(desktopPath, fileName);

                File.WriteAllBytes(fullPath, bytes);

                // 7. Show Success Message
                StatusLabel.Text = $"Saved to Desktop:\n{fileName}";
                StatusLabel.TextColor = Colors.Green;
            }
            catch (Exception ex)
            {
                StatusLabel.Text = $"Error: {ex.Message}";
                StatusLabel.TextColor = Colors.Red;
            }
        }
    }
}
$vbLabelText   $csharpLabel

Output with Generated Barcode

Generate Barcode Success

As you can see, the application displays the generated barcode and saves it to the user's desktop.

Output Failure

Generate Barcode Failure

Certain barcode types have restrictions and format requirements for the input value. When the barcode fails to generate, the application displays the IronBarcode exception, as shown above. Please refer to the respective detailed 1D and 2D for formatting for each barcode type.

To test the examples above (Desktop Barcode Scanner and the Desktop Barcode Generator), please download this sample project.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More
Ready to Get Started?
Nuget Downloads 2,015,591 | Version: 2025.12 just released