Parking Move QR Code Generation Tool Development Practice

Parking Move QR Code Generation Tool Development Practice

This article introduces how to develop a parking move QR code generation tool, including a desktop version implemented with C# and Avalonia, as well as an online version implemented with Blazor frontend and .NET Web API, covering requirements analysis, core code implementation, UI design, and application of MVVM pattern.

Last updated 3/10/2025 7:54 PM
沙漠尽头的狼
20 min read
Category
.NET
Tags
.NET C# Blazor Avalonia UI MVVM

1. Requirements Analysis and Solution Design

Background Problem

In modern bustling cities, parking difficulties are ever-present, and moving vehicles has become one of the everyday troubles for car owners. In the past, to make it convenient for others to contact them for vehicle relocation, people often placed a note with their phone number in a conspicuous location inside the car, or used a car ornament engraved with their mobile number. This traditional method seems simple and straightforward, but it harbors many risks.

The first issue is privacy leakage. Today, personal information security is of utmost importance. Exposing your phone number in a public place is like leaving the door wide open to your privacy. Criminals can exploit this information for malicious harassment, with spam calls and scam text messages flooding in, causing great annoyance. There have been news reports of so-called "number collectors" roaming parking lots, gathering parking contact numbers and then selling them in bulk to marketing companies or fraud rings, leaving car owners' lives filled with all kinds of junk messages.

Besides privacy leakage, the misuse of parking contact numbers is also common. Sometimes, even for a brief temporary stop, owners receive constant calls asking them to move their car, and some people call unnecessarily in non-urgent situations, wasting the owner's time. More seriously, malicious individuals may use the parking contact number to commit fraud, using false excuses such as traffic violations or accidents to trick owners into clicking links or transferring money, resulting in property loss.

Solution

To address the above issues, we have developed a simple and practical QR code generator for vehicle relocation, implementing the following features:

  1. Quickly generate a QR code containing the owner's contact information
  2. Scan the code to call the owner with one tap
  3. Support custom parking notification text
  4. Mobile phone numbers are encrypted to protect owner privacy
  5. Provide both offline desktop and online web versions

Unlike the traditional method of directly displaying a phone number, our parking QR code tool uses encryption technology to ensure the owner's phone number is not directly exposed. At the same time, scanning the code redirects to a dedicated vehicle relocation page, which enhances the user experience and reduces the risk of number misuse. This article will detail these two implementations: the desktop application version based on C# and Avalonia, and the online web version based on Blazor frontend and .NET Web API.

The effect is as follows; scanning with WeChat displays the detail page:

On the detail page, you can click Call the owner or click the green hyperlink Go generate a parking QR code:

2. Core QR Code Generation Code

First, let's look at the core QR code generation logic. This part is encapsulated in the QrCodeGenerator class of the CodeWF.Tools project:

using ImageMagick;
using ImageMagick.Drawing;
using ZXing;
using ZXing.QrCode;

namespace CodeWF.Tools.Image;

public static class QrCodeGenerator
{
    public static void GenerateQrCode(string title, string content, string imagePath, string? subTitle = "")
    {
        var qrCodeWriter = new BarcodeWriterPixelData
        {
            Format = BarcodeFormat.QR_CODE,
            Options = new QrCodeEncodingOptions
            {
                Width = 400,
                Height = 400,
                Margin = 1,
                ErrorCorrection = ZXing.QrCode.Internal.ErrorCorrectionLevel.H,
                CharacterSet = "UTF-8",
                DisableECI = true
            }
        };

        var pixelData = qrCodeWriter.Write(content);

        using var qrCodeImage = new MagickImage();
        var settings = new PixelReadSettings((uint)pixelData.Width, (uint)pixelData.Height, StorageType.Char, PixelMapping.RGBA);
        qrCodeImage.ReadPixels(pixelData.Pixels, settings);

        var backgroundHeight = string.IsNullOrWhiteSpace(subTitle) ? 600u : 630u;
        using var background = new MagickImage(MagickColors.White, 500, backgroundHeight);

        background.BorderColor = new MagickColor("#2888E2");
        background.Border(8);

        var titleText = new Drawables()
            .Font("SimHei")
            .FontPointSize(95)
            .FillColor(new MagickColor("#FF5722"))
            .TextAlignment(TextAlignment.Center)
            .Text(250, 120, title);
        background.Draw(titleText);

        background.Composite(qrCodeImage, 50, 170, CompositeOperator.Over);

        if (!string.IsNullOrWhiteSpace(subTitle))
        {
            var subTitleText = new Drawables()
                .Font("SimHei")
                .FontPointSize(20)
                .FillColor(new MagickColor("#333333"))
                .TextAlignment(TextAlignment.Center)
                .Text(250, 600, subTitle);
            background.Draw(subTitleText);
        }

        //using var logo = new MagickImage("logo.png");
        //logo.Resize(100, 100);
        //background.Composite(logo, 250, 250, CompositeOperator.Over);

        background.Quality = 100;
        background.Write(imagePath);
    }
}

The above code uses NuGet packages: ZXing.Net.Bindings.Magick. ZXing.NET generates the QR code matrix data, while Magick.NET handles image processing and composition, implementing the following features:

  1. Create a high-quality QR code with a high error correction level (level H), so that even if part of the code is blocked it can still be recognized
  2. Generate a background image with white background and blue border
  3. Add custom title text at the top
  4. Composite the QR code image onto the background
  5. Optionally add custom subtitle text below the QR code
  6. Save as a high-quality PNG image

This design makes the final vehicle relocation QR code both beautiful and practical.

Vehicle Relocation QR Code

3. Offline Desktop Version Implementation

3.1 User Interface Design

Using the Avalonia framework to design the user interface, defined in the NuoCheView.axaml file:

<UserControl xmlns="https://github.com/avaloniaui"
             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:vm="clr-namespace:CodeWF.Modules.Converter.ViewModels"
             xmlns:prism="http://prismlibrary.com/"
             xmlns:u="https://irihi.tech/ursa"
             xmlns:i18n="https://codewf.com"
             xmlns:language="clr-namespace:Localization"
             prism:ViewModelLocator.AutoWireViewModel="True"
             x:CompileBindings="True"
             x:DataType="vm:NuoCheViewModel"
             d:DesignHeight="450"
             d:DesignWidth="800"
             x:Class="CodeWF.Modules.Converter.Views.NuoCheView"
             mc:Ignorable="d">
    <StackPanel Margin="10" HorizontalAlignment="Center">
        <u:Form LabelPosition="Left" LabelWidth="*">
            <TextBox Width="300" u:FormItem.Label="{i18n:I18n {x:Static language:NuoCheView.InputPhoneNumber}}"
                     u:FormItem.IsRequired="True" Text="{Binding PhoneNumber}" />
            <TextBox Width="300" u:FormItem.Label="{i18n:I18n {x:Static language:NuoCheView.InputTitle}}"
                     u:FormItem.IsRequired="True" Text="{Binding InputTitle}" />
            <StackPanel Orientation="Horizontal" u:FormItem.Label="{i18n:I18n {x:Static language:NuoCheView.EnableSubTitle}}">
                <CheckBox IsChecked="{Binding EnableSubTitle}" Command="{Binding EnableSubTitleHandler}" VerticalAlignment="Center" Content="Display" Margin="5 0" />
                <TextBox Width="300" Text="{Binding SubTitle}" IsEnabled="{Binding EnableSubTitle}" VerticalAlignment="Center" />
            </StackPanel>
        </u:Form>

        <StackPanel Orientation="Horizontal" Spacing="10" Margin="0,0,0,10">
            <Button Content="{i18n:I18n {x:Static language:NuoCheView.CreateButtonContent}}"
                    Command="{Binding GenerateQrCode}" />
            <Button Content="{i18n:I18n {x:Static language:NuoCheView.SaveQrCodeFileTitle}}"
                    Command="{Binding SaveQrCode}" />
            <HyperlinkButton Content="{i18n:I18n {x:Static language:NuoCheView.PreviewNuoCheUrl}}"
                             NavigateUri="{Binding GeneratedUrl}" Classes="WithIcon Underline"
                             VerticalAlignment="Center" />
        </StackPanel>

        <Image Source="{Binding QrCodeImage}" Width="340" Height="340" DragDrop.AllowDrop="True">
            <Interaction.Behaviors>
                <EventTriggerBehavior EventName="PointerPressed">
                    <InvokeCommandAction Command="{Binding RaisePointerPressed}" PassEventArgsToCommand="True" />
                </EventTriggerBehavior>
            </Interaction.Behaviors>
        </Image>
    </StackPanel>
</UserControl>

The interface layout is clean and straightforward, mainly including:

  1. Three input fields: phone number, QR code title, optional QR code subtitle
  2. Three action buttons: generate QR code, save QR code, and preview vehicle relocation page
  3. One image display area: shows the generated QR code and supports drag operations

The implemented effect is as follows:

Offline version interface screenshot

3.2 ViewModel Implementation

Business logic is implemented in NuoCheViewModel.cs:

using Avalonia.Input;
using Avalonia.Media.Imaging;
using Avalonia.Platform.Storage;
using AvaloniaXmlTranslator;
using CodeWF.Core.IServices;
using CodeWF.LogViewer.Avalonia;
using CodeWF.Tools.Image;
using HashidsNet;
using ReactiveUI;

namespace CodeWF.Modules.Converter.ViewModels;

public class NuoCheViewModel : ReactiveObject
{
    private readonly INotificationService _notificationService;
    private readonly IFileChooserService _fileChooserService;
    private string _inputTitle;
    private long _phoneNumber;
    private Bitmap? _qrCodeImage;
    private string _qrCodeImagePath;
    private string _generatedUrl;
    private string _subTitle;
    private bool _enableSubTitle;

    public NuoCheViewModel(INotificationService notificationService, IFileChooserService fileChooserService)
    {
        _notificationService = notificationService;
        _fileChooserService = fileChooserService;

        InputTitle = I18nManager.Instance.GetResource(Localization.NuoCheView.DefaultInputTitle);
        PhoneNumber = 16899999999;
        SubTitle = $"{I18nManager.Instance.GetResource(Localization.NuoCheView.DefaultSubTitlePrefix)}: {PhoneNumber}";
        EnableSubTitle = false;
    }

    public string InputTitle
    {
        get => _inputTitle;
        set => this.RaiseAndSetIfChanged(ref _inputTitle, value);
    }

    public long PhoneNumber
    {
        get => _phoneNumber;
        set => this.RaiseAndSetIfChanged(ref _phoneNumber, value);
    }

    public Bitmap? QrCodeImage
    {
        get => _qrCodeImage;
        private set => this.RaiseAndSetIfChanged(ref _qrCodeImage, value);
    }

    public string QrCodeImagePath
    {
        get => _qrCodeImagePath;
        private set => this.RaiseAndSetIfChanged(ref _qrCodeImagePath, value);
    }

    public string GeneratedUrl
    {
        get => _generatedUrl;
        private set => this.RaiseAndSetIfChanged(ref _generatedUrl, value);
    }

    public string SubTitle
    {
        get => _subTitle;
        set => this.RaiseAndSetIfChanged(ref _subTitle, value);
    }

    public bool EnableSubTitle
    {
        get => _enableSubTitle;
        set => this.RaiseAndSetIfChanged(ref _enableSubTitle, value);
    }

    public void EnableSubTitleHandler()
    {
        SubTitle = $"{I18nManager.Instance.GetResource(Localization.NuoCheView.DefaultSubTitlePrefix)}: {PhoneNumber}";
    }

    public void GenerateQrCode()
    {
        if (string.IsNullOrWhiteSpace(InputTitle))
        {
            _notificationService.Show(I18nManager.Instance.GetResource(Localization.NuoCheView.Title),
                I18nManager.Instance.GetResource(Localization.NuoCheView.NeedInputTip));
            return;
        }

        try
        {
            var encodedPhone = new Hashids("codewf").EncodeLong(PhoneNumber);

            GeneratedUrl =
                $"https://codewf.com/nuoche?p={encodedPhone}";
            QrCodeImagePath = Path.Combine(Path.GetTempPath(), "nuoche.png");

            QrCodeGenerator.GenerateQrCode(InputTitle, GeneratedUrl, QrCodeImagePath, 
                EnableSubTitle ? SubTitle : null);

            QrCodeImage = new Bitmap(QrCodeImagePath);
        }
        catch (Exception ex)
        {
            Logger.Error(I18nManager.Instance.GetResource(Localization.NuoCheView.CreateErrorMessage), ex);
            _notificationService.Show(I18nManager.Instance.GetResource(Localization.NuoCheView.Title),
                $"{I18nManager.Instance.GetResource(Localization.NuoCheView.CreateErrorMessage)}: {ex}");
        }
    }


    public async Task SaveQrCode()
    {
        if (QrCodeImage == null || string.IsNullOrEmpty(QrCodeImagePath))
        {
            _notificationService.Show(I18nManager.Instance.GetResource(Localization.NuoCheView.SaveNotificationTitle),
                I18nManager.Instance.GetResource(Localization.NuoCheView.SaveNoQrCodeMessage));
            return;
        }

        try
        {
            var file = await _fileChooserService.SaveFileAsync(
                I18nManager.Instance.GetResource(Localization.NuoCheView.SaveQrCodeFileTitle),
                new[]
                {
                    new FilePickerFileType(
                        I18nManager.Instance.GetResource(Localization.NuoCheView.SaveQrCodeFileFormat))
                    {
                        Patterns = new[] { "*.png" }
                    }
                }
            );

            if (file != null)
            {
                File.Copy(QrCodeImagePath, file, true);
                _notificationService.Show(
                    I18nManager.Instance.GetResource(Localization.NuoCheView.SaveQrCodeSuccessTitle),
                    I18nManager.Instance.GetResource(Localization.NuoCheView.SaveQrCodeSuccessMessage));
            }
        }
        catch (Exception ex)
        {
            _notificationService.Show(I18nManager.Instance.GetResource(Localization.NuoCheView.SaveNotificationTitle),
                $"{I18nManager.Instance.GetResource(Localization.NuoCheView.SaveQrCodeErrorMessage)}: {ex.Message}");
        }
    }

    public async Task RaisePointerPressed(PointerPressedEventArgs e)
    {
        if (string.IsNullOrWhiteSpace(QrCodeImagePath) || !File.Exists(QrCodeImagePath))
        {
            return;
        }

        var dragData = new DataObject();
        if (await _fileChooserService.StorageProvider.TryGetFileFromPathAsync(QrCodeImagePath) is { } storageFile)
        {
            dragData.Set(DataFormats.Files, new[] { storageFile });
        }

        await DragDrop.DoDragDrop(e, dragData, DragDropEffects.Copy);
    }
}

The ViewModel implements the following features:

  1. Data Binding: manages user input and UI state
  2. QR Code Generation: calls the core generation logic and displays the result
  3. File Saving: saves the generated QR code to a user-specified location
  4. Drag Support: allows users to drag the QR code image directly to other applications
  5. Error Handling: provides user-friendly error messages

It's worth mentioning that we use the Hashids library to encode the phone number, improving privacy protection. Thus, even if the QR code is publicly displayed, others cannot directly obtain the owner's real phone number (of course, the final dialing interface will display the real phone number; this could be further enhanced with virtual numbers to hide the real number).

Effect of dragging and saving the vehicle relocation QR code:

Drag to save parking QR code

4. Online Web Version Implementation

In addition to the desktop version, we also developed an online vehicle relocation QR code generator based on Blazor, allowing users to use it without installing any software.

Online access: https://dotnet9.com/nuoche

Creating a parking QR code on PC:

Online PC creating parking QR code

Creating a parking QR code on mobile:

Online mobile creating parking QR code

4.1 Features of Online Parking QR Code Generator

Compared to the desktop version, the online version has the following features:

  1. No installation required: access directly via browser
  2. Bidirectional functionality: can both generate QR codes and directly access the parsed vehicle relocation page
  3. Mobile-friendly: optimized display and interaction on mobile devices
  4. Elegant UI design: uses modern UI components and interactive effects

4.2 Implementation

The online version is implemented with Blazor. The core code structure is as follows:

@page "/NuoChe"
@using HashidsNet
@inject IOptions<SiteOption> SiteOption
@layout EmptyLayout

@code {
    [SupplyParameterFromQuery]
    public string? P { get; set; }

    public const string Slug = "nuoche";

    private long? _decodePhone;

    protected override void OnInitialized()
    {
        base.OnInitialized();
        if (!string.IsNullOrWhiteSpace(P))
        {
            _decodePhone = new Hashids("codewf").DecodeLong(P)[0];
        }
    }
}

<PageTitle>Free Parking QR Code</PageTitle>

<div class="nuoche-container">
    @if (string.IsNullOrWhiteSpace(P))
    {
        <div class="generator-container">
            <h1 class="generator-title">Online Parking QR Code Generator</h1>
            <div class="input-group">
                <label for="phoneNumber">Phone Number</label>
                <input type="tel" id="phoneNumber" placeholder="Enter phone number" />
            </div>
            <div class="input-group">
                <label for="title">Title</label>
                <input type="text" id="title" placeholder="Scan to move vehicle" value="Scan to move vehicle" />
            </div>
            <div class="input-group">
                <div class="checkbox-container">
                    <input type="checkbox" id="enableSubtitle" />
                    <label for="enableSubtitle">Add subtitle</label>
                </div>
                <input type="text" id="subtitle" placeholder="Scan to contact owner or call: 16800000000" disabled />
            </div>
            <div class="button-group">
                <button class="primary-button" onclick="generateQrCode()">
                    <i class="fas fa-qrcode"></i> Generate QR Code
                </button>
            </div>
            <div class="qr-code-container" style="display: none">
                <img alt="Parking QR Code" />
                <div class="action-buttons">
                    <a target="_blank" class="preview-link">
                        <i class="fas fa-external-link-alt"></i> Preview
                    </a>
                    <a class="download-link">
                        <i class="fas fa-download"></i> Download
                    </a>
                </div>
                <div class="alert alert-warning mt-2">
                    <i class="fas fa-clock"></i> Note: The generated file is kept for only 2 minutes, please download in time.
                </div>
            </div>
        </div>
    }
    else
    {
        <div class="card">
            <div class="card-header">
                <i class="fas fa-car"></i>
                <h1 class="title">Temporarily parked, please be considerate</h1>
            </div>
            <div class="card-body">
                <p class="description">If my car is blocking your vehicle, click the button below to notify me. Sorry for the inconvenience.</p>
                <a class="phone-button" href="tel:@_decodePhone">
                    <i class="fas fa-phone-alt"></i> Call the owner
                </a>
                <a class="generate-link" href="/nuoche">Go generate a parking QR code</a>
            </div>
        </div>
    }
</div>

This implementation has two main functional pages:

  1. Generation Page: when the user directly accesses /nuoche, it displays the QR code generation interface, allowing input of phone number and title
  2. Vehicle Relocation Page: when the user accesses via QR code scanning (with the p parameter), it shows an interface with a one-tap call to the owner

With this design, we achieve the complete lifecycle of the QR code: generate, scan, contact, providing a convenient vehicle relocation solution for users.

Screenshot after scanning showing the detail page:

Screenshot after scanning

4.3 Core JavaScript Interaction for Online Version

async function generateQrCode() {
    const title = document.getElementById('title').value;
    const phoneNumber = document.getElementById('phoneNumber').value;
    const enableSubtitle = document.getElementById('enableSubtitle').checked;
    let subtitle = null;
    
    if (enableSubtitle) {
        subtitle = document.getElementById('subtitle').value.trim();
        if (!subtitle) {
            subtitle = `Scan to contact owner or call: ${phoneNumber || "16800000000"}`;
            document.getElementById('subtitle').value = subtitle;
        }
    }

    if (!title || !phoneNumber) {
        alert('Please enter title and phone number');
        return;
    }

    try {
        const response = await fetch('/api/Image/nuoche', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                title: title,
                phoneNumber: phoneNumber,
                subtitle: subtitle
            })
        });

        const data = await response.json();
        if (data.success) {
            const qrCodeContainer = document.querySelector('.qr-code-container');
            const img = qrCodeContainer.querySelector('img');
            img.src = data.qrCodeUrl;
            qrCodeContainer.querySelector('.preview-link').href = data.generatedUrl;

            // Add download functionality
            const downloadLink = qrCodeContainer.querySelector('.download-link');
            downloadLink.onclick = () => {
                const a = document.createElement('a');
                a.href = data.qrCodeUrl;
                a.download = 'parking_qr.png';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
            };

            qrCodeContainer.style.display = 'block';
        } else {
            throw new Error(data.message);
        }
    } catch (error) {
        console.error('Failed to generate QR code:', error);
        alert('Failed to generate QR code, please try again later');
    }
}

// Event handling for subtitle checkbox
document.addEventListener('DOMContentLoaded', function() {
    const enableSubtitleCheckbox = document.getElementById('enableSubtitle');
    const subtitleInput = document.getElementById('subtitle');
    const phoneInput = document.getElementById('phoneNumber');
    
    if (enableSubtitleCheckbox && subtitleInput) {
        enableSubtitleCheckbox.addEventListener('change', function() {
            subtitleInput.disabled = !this.checked;
            if (this.checked) {
                if (!subtitleInput.value.trim()) {
                    const phoneNumber = phoneInput.value.trim() || "16800000000";
                    subtitleInput.value = `Scan to contact owner or call: ${phoneNumber}`;
                }
                subtitleInput.focus();
            }
        });
        
        // When phone number changes, if subtitle is enabled and using the default format, update the phone number in subtitle
        phoneInput.addEventListener('input', function() {
            if (enableSubtitleCheckbox.checked && subtitleInput.value.startsWith('Scan to contact owner or call:')) {
                const phoneNumber = this.value.trim() || "16800000000";
                subtitleInput.value = `Scan to contact owner or call: ${phoneNumber}`;
            }
        });
    }
});

The backend API for the online version is similar to the offline version, using the same core QR code generation logic, but adds file upload handling, temporary storage, and cleanup. We won't elaborate further here; the online version source code is available. The parking QR code API endpoint is defined as follows:

[HttpPost("nuoche")]
[AllowAnonymous]
public async Task<IActionResult> NuoCheAsync([FromBody] NuoCheRequest request,
    [FromServices] IWebHostEnvironment env,
    [FromServices] IOptions<SiteOption> siteOption)
{
    try
    {
        if (string.IsNullOrWhiteSpace(request.Title) || string.IsNullOrWhiteSpace(request.PhoneNumber))
        {
            return BadRequest(new { success = false, message = "Title and phone number cannot be empty" });
        }

        if (!long.TryParse(request.PhoneNumber, out long phoneNumberLong))
        {
            return BadRequest(new { success = false, message = "Invalid phone number" });
        }

        var encodedPhone = new Hashids("codewf").EncodeLong(phoneNumberLong);
        var generatedUrl = $"{siteOption.Value.Domain}/nuoche?p={encodedPhone}";

        var fileName = $"qrcode_{Guid.NewGuid():N}.png";
        var qrCodePath = Path.Combine(env.WebRootPath, IconFolder, fileName);

        Directory.CreateDirectory(Path.Combine(env.WebRootPath, IconFolder));

        QrCodeGenerator.GenerateQrCode(request.Title, generatedUrl, qrCodePath, request.SubTitle);

        var qrCodeUrl = $"/{IconFolder}/{fileName}";
        return Ok(new
        {
            success = true,
            qrCodeUrl,
            generatedUrl
        });
    }
    catch (Exception ex)
    {
        return BadRequest(new { success = false, message = ex.Message });
    }
}

5. Feature Comparison and Application Scenarios

The offline desktop version and the online web version each have their strengths. Below is a comparison of their features:

Feature Offline Version Online Version
Installation Download required No installation, browser access
Platform Support Windows, macOS, Linux Any modern browser
Network Dependency Only initial URL generation needs network Fully dependent on network
File Storage Permanent local storage Temporary server storage
UI Experience Desktop application style Responsive web design
Drag Support Supports dragging QR code image No direct drag support
Privacy Protection High (local processing) Medium (server processing)
Subtitle Feature Supports custom subtitle Supports custom subtitle

The addition of the subtitle feature makes the QR code more informative, allowing extra hints to be added below the code (such as "Scan to contact owner" or displaying partial contact information), enhancing recognizability and ease of use.

6. Summary and Outlook

In this article, we have detailed the development process of the vehicle relocation QR code generator, including requirements analysis, core code implementation, UI design, and multi-platform deployment. This tool not only solves the privacy leakage and number misuse problems associated with traditional vehicle relocation contact methods, but also provides a safer and more convenient experience through modern technology.

This tool is particularly useful in the following scenarios:

  1. Temporary Parking: providing contact information when parking temporarily in residential areas, shopping malls, etc.
  2. Car Shows and Events: placing easily reachable QR codes when displaying vehicles
  3. Shared Parking Spaces: providing temporary contact on private parking spaces
  4. Emergency Situations: when a vehicle needs urgent contact with the owner for special reasons

In the future, we plan to further improve this tool. Possible directions for enhancement include:

  1. Multi-language Support: adding English, Japanese and other language interfaces for international users
  2. More Customization Options: supporting custom QR code colors, styles, and layouts
  3. Statistics: adding scan count statistics to help users understand QR code usage
  4. Enterprise Version: providing batch generation for fleet management, parking lots, etc.

As a practical tool, the vehicle relocation QR code generator solves real-life problems while also demonstrating how to build cross-platform applications using the modern .NET technology stack.

We hope this article has been helpful. If you have any questions, feel free to leave a comment!

Source code reference:

Keep Exploring

Related Reading

More Articles
Same category / Same tag 2/25/2025

.NET 10 Preview 1 Released

Today .NET 10 Preview 1 was released. I downloaded it immediately, upgraded the Avalonia UI project and blog website. The former passed functional testing and AOT publishing successfully, the latter debugging went fine, but Docker has not been successful yet.

Continue Reading