C# USB-Barcodescanner: Erstellen Sie eine vollständige Scan-Anwendung
USB-Barcodescanner werden von C#-Anwendungen als Standard-Tastatureingabegeräte verwendet und senden die gescannten Daten als eingegebene Zeichen, gefolgt von einem Tastendruck auf die Eingabetaste. Dieses HID-Tastatur-Wedge-Verhalten macht die Integration unkompliziert – Ihre Anwendung empfängt Texteingaben ohne dass ein spezieller Treiber oder ein SDK erforderlich ist. IronBarcode verarbeitet diese Rohdaten, um Formate zu validieren, strukturierte Daten zu extrahieren und Antwort-Barcodes zu generieren. So wird aus einem einfachen Scanvorgang eine vollständige Datenpipeline für Bestandsverwaltung, Kassensysteme im Einzelhandel und Logistik-Tracking-Systeme.
Einzelhandel, Lagerhaltung und Fertigung – alle sind auf ein genaues und schnelles Scannen von Barcodes angewiesen. Wenn ein Entwickler einen USB-Scanner an eine Windows Forms- oder WPF-Anwendung anschließt, verhält sich der Scanner identisch zu einer Tastatur – die Daten kommen in einem Textfeld an, und das Drücken der Eingabetaste signalisiert, dass ein vollständiger Barcode empfangen wurde. Die Herausforderung besteht nicht in der Datenerfassung; Es wird korrekt verarbeitet. Die Barcode-Validierungsfunktion von IronBarcode prüft die Formatintegrität, extrahiert Felder wie Chargennummern oder GS1-Anwendungskennungen und kann daraufhin sofort einen neuen Barcode generieren .
Diese Anleitung führt Sie Schritt für Schritt durch die Entwicklung einer produktionsreifen C#-USB-Barcodescanner-Anwendung. Sie installieren die Bibliothek, erfassen Scannereingaben, validieren Barcode-Formate, generieren Antwortbezeichnungen und erstellen einen Prozessor für hohe Scanvolumen mit Warteschlangen. Jeder Abschnitt enthält vollständigen, ausführbaren Code, der auf .NET 10 abzielt und gegebenenfalls Top-Level-Anweisungen verwendet.
Wie funktionieren USB-Barcodescanner mit C#?
Warum vereinfacht der HID-Tastaturkeilmodus die Integration?
Die meisten USB-Barcodescanner werden standardmäßig im HID-Tastatur-Wedge-Modus ausgeliefert. Wenn Sie ein solches Gerät an einen Windows-Rechner anschließen, erkennt das Betriebssystem es sowohl als USB-Speichergerät (zur Konfiguration) als auch als Tastatur (zur Dateneingabe). Beim Scannen eines Barcodes übersetzt das Gerät den dekodierten Barcode-Wert in Tastatureingaben und sendet diese an das jeweilige Anwendungsfenster, das den Fokus hat, wobei am Ende ein Zeilenumbruch angehängt wird.
Aus der Sicht eines C#-Entwicklers bedeutet dies, dass keine herstellerspezifischen SDKs, COM-Bibliotheken oder spezielle USB-APIs benötigt werden. Ein Standard-TextBox-Steuerelement mit einem KeyDown-Handler genügt, um Eingaben zu erfassen. Die größte Herausforderung bei der Integration besteht darin, die Eingabe durch den Scanner von der tatsächlichen Tastatureingabe zu unterscheiden. Scanner liefern typischerweise alle Zeichen in einem sehr kurzen Moment – oft unter 50 Millisekunden –, während menschliches Tippen die Tastenanschläge über Hunderte von Millisekunden verteilt. Das Timing der Tastenanschläge ist eine zuverlässige Methode, um versehentliche Tastendrücke herauszufiltern.
Professionelle Scanner unterstützen außerdem serielle Schnittstellen (RS-232 oder virtueller COM-Port) und direkte USB-HID-Modi, die Ihnen mehr Kontrolle über Präfix-/Suffixzeichen und Scan-Trigger geben. Das untenstehende Schnittstellenmuster behandelt beide Fälle:
public interface IScannerInput
{
event EventHandler<string> BarcodeScanned;
void StartListening();
void StopListening();
}
public class KeyboardWedgeScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly TextBox _inputBox;
private readonly System.Windows.Forms.Timer _burstTimer;
private readonly System.Text.StringBuilder _buffer = new();
public KeyboardWedgeScanner(TextBox inputBox)
{
_inputBox = inputBox;
_burstTimer = new System.Windows.Forms.Timer { Interval = 80 };
_burstTimer.Tick += OnBurstTimeout;
_inputBox.KeyPress += OnKeyPress;
}
private void OnKeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
_burstTimer.Stop();
string value = _buffer.ToString().Trim();
_buffer.Clear();
if (value.Length > 0)
BarcodeScanned?.Invoke(this, value);
}
else
{
_buffer.Append(e.KeyChar);
_burstTimer.Stop();
_burstTimer.Start();
}
e.Handled = true;
}
private void OnBurstTimeout(object sender, EventArgs e)
{
_burstTimer.Stop();
_buffer.Clear(); // incomplete burst -- discard
}
public void StartListening() => _inputBox.Focus();
public void StopListening() => _inputBox.Enabled = false;
}
public class SerialPortScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly System.IO.Ports.SerialPort _port;
public SerialPortScanner(string portName, int baudRate = 9600)
{
_port = new System.IO.Ports.SerialPort(portName, baudRate);
_port.DataReceived += OnDataReceived;
}
private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string data = _port.ReadLine().Trim();
if (data.Length > 0)
BarcodeScanned?.Invoke(this, data);
}
public void StartListening() => _port.Open();
public void StopListening() => _port.Close();
}
public interface IScannerInput
{
event EventHandler<string> BarcodeScanned;
void StartListening();
void StopListening();
}
public class KeyboardWedgeScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly TextBox _inputBox;
private readonly System.Windows.Forms.Timer _burstTimer;
private readonly System.Text.StringBuilder _buffer = new();
public KeyboardWedgeScanner(TextBox inputBox)
{
_inputBox = inputBox;
_burstTimer = new System.Windows.Forms.Timer { Interval = 80 };
_burstTimer.Tick += OnBurstTimeout;
_inputBox.KeyPress += OnKeyPress;
}
private void OnKeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
_burstTimer.Stop();
string value = _buffer.ToString().Trim();
_buffer.Clear();
if (value.Length > 0)
BarcodeScanned?.Invoke(this, value);
}
else
{
_buffer.Append(e.KeyChar);
_burstTimer.Stop();
_burstTimer.Start();
}
e.Handled = true;
}
private void OnBurstTimeout(object sender, EventArgs e)
{
_burstTimer.Stop();
_buffer.Clear(); // incomplete burst -- discard
}
public void StartListening() => _inputBox.Focus();
public void StopListening() => _inputBox.Enabled = false;
}
public class SerialPortScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly System.IO.Ports.SerialPort _port;
public SerialPortScanner(string portName, int baudRate = 9600)
{
_port = new System.IO.Ports.SerialPort(portName, baudRate);
_port.DataReceived += OnDataReceived;
}
private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string data = _port.ReadLine().Trim();
if (data.Length > 0)
BarcodeScanned?.Invoke(this, data);
}
public void StartListening() => _port.Open();
public void StopListening() => _port.Close();
}
Imports System
Imports System.Text
Imports System.Windows.Forms
Imports System.IO.Ports
Public Interface IScannerInput
Event BarcodeScanned As EventHandler(Of String)
Sub StartListening()
Sub StopListening()
End Interface
Public Class KeyboardWedgeScanner
Implements IScannerInput
Public Event BarcodeScanned As EventHandler(Of String) Implements IScannerInput.BarcodeScanned
Private ReadOnly _inputBox As TextBox
Private ReadOnly _burstTimer As Timer
Private ReadOnly _buffer As New StringBuilder()
Public Sub New(inputBox As TextBox)
_inputBox = inputBox
_burstTimer = New Timer With {.Interval = 80}
AddHandler _burstTimer.Tick, AddressOf OnBurstTimeout
AddHandler _inputBox.KeyPress, AddressOf OnKeyPress
End Sub
Private Sub OnKeyPress(sender As Object, e As KeyPressEventArgs)
If e.KeyChar = ChrW(Keys.Enter) Then
_burstTimer.Stop()
Dim value As String = _buffer.ToString().Trim()
_buffer.Clear()
If value.Length > 0 Then
RaiseEvent BarcodeScanned(Me, value)
End If
Else
_buffer.Append(e.KeyChar)
_burstTimer.Stop()
_burstTimer.Start()
End If
e.Handled = True
End Sub
Private Sub OnBurstTimeout(sender As Object, e As EventArgs)
_burstTimer.Stop()
_buffer.Clear() ' incomplete burst -- discard
End Sub
Public Sub StartListening() Implements IScannerInput.StartListening
_inputBox.Focus()
End Sub
Public Sub StopListening() Implements IScannerInput.StopListening
_inputBox.Enabled = False
End Sub
End Class
Public Class SerialPortScanner
Implements IScannerInput
Public Event BarcodeScanned As EventHandler(Of String) Implements IScannerInput.BarcodeScanned
Private ReadOnly _port As SerialPort
Public Sub New(portName As String, Optional baudRate As Integer = 9600)
_port = New SerialPort(portName, baudRate)
AddHandler _port.DataReceived, AddressOf OnDataReceived
End Sub
Private Sub OnDataReceived(sender As Object, e As SerialDataReceivedEventArgs)
Dim data As String = _port.ReadLine().Trim()
If data.Length > 0 Then
RaiseEvent BarcodeScanned(Me, data)
End If
End Sub
Public Sub StartListening() Implements IScannerInput.StartListening
_port.Open()
End Sub
Public Sub StopListening() Implements IScannerInput.StopListening
_port.Close()
End Sub
End Class
Der entscheidende Punkt ist der Burst-Timer in der Tastatur-Wedge-Implementierung. Es wird bei jedem Tastendruck zurückgesetzt und nur ausgelöst, wenn keine Zeichen mehr eintreffen – das bedeutet, dass bei echten Tastaturbenutzern, die langsam tippen, die unvollständige Eingabe verworfen und nicht wie ein Barcode-Scan behandelt wird.
Wie handhabt man verschiedene Scannermarken?
In Enterprise werden häufig verschiedene Scanner von Honeywell, Zebra (ehemals Symbol/Motorola) und Datalogic auf derselben Etage eingesetzt. Jeder Anbieter hat seine eigenen Standard-Abschlusszeichen, Baudraten und Präfix-/Suffixkonventionen. Ein Konfigurationsmodell sorgt für Flexibilität Ihrer Anwendung:
public class ScannerConfiguration
{
public string ScannerType { get; set; } = "KeyboardWedge";
public string PortName { get; set; } = "COM3";
public int BaudRate { get; set; } = 9600;
public string Terminator { get; set; } = "\r\n";
public bool EnableBeep { get; set; } = true;
public Dictionary<string, string> BrandSettings { get; set; } = new();
public static ScannerConfiguration GetHoneywellConfig() => new()
{
ScannerType = "Serial",
BaudRate = 115200,
BrandSettings = new Dictionary<string, string>
{
{ "Prefix", "STX" },
{ "Suffix", "ETX" },
{ "TriggerMode", "Manual" }
}
};
public static ScannerConfiguration GetZebraConfig() => new()
{
ScannerType = "KeyboardWedge",
BrandSettings = new Dictionary<string, string>
{
{ "ScanMode", "Continuous" },
{ "BeepVolume", "High" }
}
};
}
public class ScannerConfiguration
{
public string ScannerType { get; set; } = "KeyboardWedge";
public string PortName { get; set; } = "COM3";
public int BaudRate { get; set; } = 9600;
public string Terminator { get; set; } = "\r\n";
public bool EnableBeep { get; set; } = true;
public Dictionary<string, string> BrandSettings { get; set; } = new();
public static ScannerConfiguration GetHoneywellConfig() => new()
{
ScannerType = "Serial",
BaudRate = 115200,
BrandSettings = new Dictionary<string, string>
{
{ "Prefix", "STX" },
{ "Suffix", "ETX" },
{ "TriggerMode", "Manual" }
}
};
public static ScannerConfiguration GetZebraConfig() => new()
{
ScannerType = "KeyboardWedge",
BrandSettings = new Dictionary<string, string>
{
{ "ScanMode", "Continuous" },
{ "BeepVolume", "High" }
}
};
}
Option Strict On
Public Class ScannerConfiguration
Public Property ScannerType As String = "KeyboardWedge"
Public Property PortName As String = "COM3"
Public Property BaudRate As Integer = 9600
Public Property Terminator As String = vbCrLf
Public Property EnableBeep As Boolean = True
Public Property BrandSettings As Dictionary(Of String, String) = New Dictionary(Of String, String)()
Public Shared Function GetHoneywellConfig() As ScannerConfiguration
Return New ScannerConfiguration() With {
.ScannerType = "Serial",
.BaudRate = 115200,
.BrandSettings = New Dictionary(Of String, String) From {
{"Prefix", "STX"},
{"Suffix", "ETX"},
{"TriggerMode", "Manual"}
}
}
End Function
Public Shared Function GetZebraConfig() As ScannerConfiguration
Return New ScannerConfiguration() With {
.ScannerType = "KeyboardWedge",
.BrandSettings = New Dictionary(Of String, String) From {
{"ScanMode", "Continuous"},
{"BeepVolume", "High"}
}
}
End Function
End Class
Durch das Speichern dieser Konfigurationen in einer Einstellungsdatei oder Datenbank können die Lagermitarbeiter die Scannermodelle austauschen, ohne dass eine erneute Bereitstellung erforderlich ist. Das Feld ScannerType steuert, welche IScannerInput Implementierung beim Start instanziiert wird.
Wie installiert man IronBarcode in einem C#-Projekt?
Wie kann IronBarcode am schnellsten über NuGet hinzugefügt werden?
Öffnen Sie die Paketmanager-Konsole in Visual Studio und führen Sie den Befehl aus:
Install-Package IronBarCode
Install-Package IronBarCode
Alternativ können Sie die .NET -Befehlszeilenschnittstelle verwenden:
dotnet add package IronBarCode
dotnet add package IronBarCode
Beide Befehle laden die aktuelle Version von NuGet herunter und fügen den Assemblyverweis zu Ihrer Projektdatei hinzu. Die Bibliothek ist for .NET Standard 2.0 ausgelegt und funktioniert daher ohne zusätzliche Kompatibilitätsschnittstellen unter .NET Framework 4.6.2 bis .NET 10.
Nach der Installation müssen Sie Ihren Lizenzschlüssel festlegen, bevor Sie eine beliebige IronBarcode -Methode aufrufen. Für Entwicklungs- und Evaluierungszwecke ist ein kostenloser Testschlüssel auf derIronBarcode -Lizenzseite erhältlich:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
Für containerisierte Bereitstellungen arbeitet IronBarcode mit Docker unter Linux zusammen , und für Cloud-Funktionen unterstützt es AWS Lambda und Azure Functions .
Wie validiert man gescannte Barcodes mit IronBarcode?
Welcher Ansatz ist für die Formatverifizierung der richtige?
IronBarcode unterstützt über 30 Barcode-Symbologien, darunter Code 128 , EAN-13 , Code 39 , QR-Codes und Data Matrix . Bei USB-Scanneranwendungen wird die gescannte Zeichenkette durch das Validierungsmuster als Barcode-Bild neu codiert und sofort wieder durch den Decoder eingelesen. Dieser Roundtrip bestätigt, dass die Zeichenkette ein gültiger Wert für das angegebene Format ist:
public class BarcodeValidator
{
public async Task<ValidationResult> ValidateAsync(string scannedText, BarcodeEncoding preferredFormat = BarcodeEncoding.Code128)
{
var result = new ValidationResult { RawInput = scannedText };
try
{
var barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat);
var readResults = await BarcodeReader.ReadAsync(barcode.ToBitmap());
if (readResults.Any())
{
var first = readResults.First();
result.IsValid = true;
result.Format = first.BarcodeType;
result.Value = first.Value;
result.Confidence = first.Confidence;
}
else
{
result.IsValid = false;
result.Error = "No barcode could be decoded from the scanned input.";
}
}
catch (Exception ex)
{
result.IsValid = false;
result.Error = ex.Message;
}
return result;
}
}
public record ValidationResult
{
public string RawInput { get; init; } = "";
public bool IsValid { get; set; }
public BarcodeEncoding Format { get; set; }
public string Value { get; set; } = "";
public float Confidence { get; set; }
public string Error { get; set; } = "";
}
public class BarcodeValidator
{
public async Task<ValidationResult> ValidateAsync(string scannedText, BarcodeEncoding preferredFormat = BarcodeEncoding.Code128)
{
var result = new ValidationResult { RawInput = scannedText };
try
{
var barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat);
var readResults = await BarcodeReader.ReadAsync(barcode.ToBitmap());
if (readResults.Any())
{
var first = readResults.First();
result.IsValid = true;
result.Format = first.BarcodeType;
result.Value = first.Value;
result.Confidence = first.Confidence;
}
else
{
result.IsValid = false;
result.Error = "No barcode could be decoded from the scanned input.";
}
}
catch (Exception ex)
{
result.IsValid = false;
result.Error = ex.Message;
}
return result;
}
}
public record ValidationResult
{
public string RawInput { get; init; } = "";
public bool IsValid { get; set; }
public BarcodeEncoding Format { get; set; }
public string Value { get; set; } = "";
public float Confidence { get; set; }
public string Error { get; set; } = "";
}
Imports System
Imports System.Linq
Imports System.Threading.Tasks
Public Class BarcodeValidator
Public Async Function ValidateAsync(scannedText As String, Optional preferredFormat As BarcodeEncoding = BarcodeEncoding.Code128) As Task(Of ValidationResult)
Dim result As New ValidationResult With {.RawInput = scannedText}
Try
Dim barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat)
Dim readResults = Await BarcodeReader.ReadAsync(barcode.ToBitmap())
If readResults.Any() Then
Dim first = readResults.First()
result.IsValid = True
result.Format = first.BarcodeType
result.Value = first.Value
result.Confidence = first.Confidence
Else
result.IsValid = False
result.Error = "No barcode could be decoded from the scanned input."
End If
Catch ex As Exception
result.IsValid = False
result.Error = ex.Message
End Try
Return result
End Function
End Class
Public Class ValidationResult
Public Property RawInput As String = ""
Public Property IsValid As Boolean
Public Property Format As BarcodeEncoding
Public Property Value As String = ""
Public Property Confidence As Single
Public Property Error As String = ""
End Class
Bei GS1-128-Barcodes , die in Supply-Chain-Anwendungen verwendet werden, enthält die gescannte Zeichenkette Anwendungsidentifikatorpräfixe in Klammern, wie z. B. (01) für GTIN und (17) für das Ablaufdatum. IronBarcode analysiert diese Anwendungsbezeichner automatisch, wenn Sie BarcodeEncoding.GS1_128 angeben.
Welche EAN-13-Prüfsummenlogik sollten Entwickler implementieren?
Kassensysteme im Einzelhandel müssen häufig die Prüfziffern der EAN-13-Nummer separat verifizieren, bevor der Wert an eine Preisabfrage übergeben wird. Die Luhn-Prüfsumme für EAN-13 verwendet abwechselnd die Gewichtungen 1 und 3 für die ersten 12 Ziffern.
public static bool ValidateEan13Checksum(string value)
{
if (value.Length != 13 || !value.All(char.IsDigit))
return false;
int sum = 0;
for (int i = 0; i < 12; i++)
{
int digit = value[i] - '0';
sum += (i % 2 == 0) ? digit : digit * 3;
}
int expectedCheck = (10 - (sum % 10)) % 10;
return expectedCheck == (value[12] - '0');
}
public static bool ValidateEan13Checksum(string value)
{
if (value.Length != 13 || !value.All(char.IsDigit))
return false;
int sum = 0;
for (int i = 0; i < 12; i++)
{
int digit = value[i] - '0';
sum += (i % 2 == 0) ? digit : digit * 3;
}
int expectedCheck = (10 - (sum % 10)) % 10;
return expectedCheck == (value[12] - '0');
}
Public Shared Function ValidateEan13Checksum(value As String) As Boolean
If value.Length <> 13 OrElse Not value.All(AddressOf Char.IsDigit) Then
Return False
End If
Dim sum As Integer = 0
For i As Integer = 0 To 11
Dim digit As Integer = AscW(value(i)) - AscW("0"c)
sum += If(i Mod 2 = 0, digit, digit * 3)
Next
Dim expectedCheck As Integer = (10 - (sum Mod 10)) Mod 10
Return expectedCheck = (AscW(value(12)) - AscW("0"c))
End Function
Diese rein logische Prüfung wird vor der Kodierung durchgeführt, um den Aufwand der Bildgenerierung für jeden Scan in einer Einzelhandelsumgebung mit hohem Durchsatz zu vermeiden. Gemäß der GS1-Spezifikation ist der Prüfziffernalgorithmus für UPC-A (12 Ziffern) identisch, wenn man die führende Null weglässt.
Wie generiert man Antwort-Barcodes aus gescannten Eingaben?
Wann sollte eine Anwendung nach einem Scan neue Barcodes erstellen?
Ein gängiges Muster bei der Warenannahme im Lager ist der Arbeitsablauf "Scannen und Neuetikettieren": Ein eingehender Artikel trägt einen Lieferanten-Barcode (oft EAN-13 oder ITF-14), und das Lagerverwaltungssystem muss ein internes Code-128-Etikett mit eigenen Standort- und Chargencodes drucken. Die Generierungsfunktionen von IronBarcode erledigen dies in wenigen Zeilen:
public class InventoryLabelGenerator
{
private readonly string _outputDirectory;
public InventoryLabelGenerator(string outputDirectory)
{
_outputDirectory = outputDirectory;
Directory.CreateDirectory(_outputDirectory);
}
public async Task<string> GenerateLabelAsync(string internalCode, string locationCode)
{
string fullCode = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}";
// Primary Code 128 label for scanners
var linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128);
linearBarcode.ResizeTo(500, 140);
linearBarcode.SetMargins(12);
linearBarcode.AddAnnotationTextAboveBarcode(fullCode);
linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black);
// QR code companion for mobile apps
var qrCode = BarcodeWriter.CreateQrCode(fullCode);
qrCode.ResizeTo(200, 200);
qrCode.SetMargins(8);
string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
string pngPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png");
string pdfPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf");
await Task.Run(() =>
{
linearBarcode.SaveAsPng(pngPath);
linearBarcode.SaveAsPdf(pdfPath);
});
return pngPath;
}
}
public class InventoryLabelGenerator
{
private readonly string _outputDirectory;
public InventoryLabelGenerator(string outputDirectory)
{
_outputDirectory = outputDirectory;
Directory.CreateDirectory(_outputDirectory);
}
public async Task<string> GenerateLabelAsync(string internalCode, string locationCode)
{
string fullCode = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}";
// Primary Code 128 label for scanners
var linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128);
linearBarcode.ResizeTo(500, 140);
linearBarcode.SetMargins(12);
linearBarcode.AddAnnotationTextAboveBarcode(fullCode);
linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black);
// QR code companion for mobile apps
var qrCode = BarcodeWriter.CreateQrCode(fullCode);
qrCode.ResizeTo(200, 200);
qrCode.SetMargins(8);
string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
string pngPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png");
string pdfPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf");
await Task.Run(() =>
{
linearBarcode.SaveAsPng(pngPath);
linearBarcode.SaveAsPdf(pdfPath);
});
return pngPath;
}
}
Imports System.IO
Imports System.Threading.Tasks
Public Class InventoryLabelGenerator
Private ReadOnly _outputDirectory As String
Public Sub New(outputDirectory As String)
_outputDirectory = outputDirectory
Directory.CreateDirectory(_outputDirectory)
End Sub
Public Async Function GenerateLabelAsync(internalCode As String, locationCode As String) As Task(Of String)
Dim fullCode As String = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}"
' Primary Code 128 label for scanners
Dim linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128)
linearBarcode.ResizeTo(500, 140)
linearBarcode.SetMargins(12)
linearBarcode.AddAnnotationTextAboveBarcode(fullCode)
linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black)
' QR code companion for mobile apps
Dim qrCode = BarcodeWriter.CreateQrCode(fullCode)
qrCode.ResizeTo(200, 200)
qrCode.SetMargins(8)
Dim timestamp As String = DateTime.UtcNow.ToString("yyyyMMddHHmmss")
Dim pngPath As String = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png")
Dim pdfPath As String = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf")
Await Task.Run(Sub()
linearBarcode.SaveAsPng(pngPath)
linearBarcode.SaveAsPdf(pdfPath)
End Sub)
Return pngPath
End Function
End Class
Das Speichern als PDF ist besonders nützlich für Etikettendrucker, die PDF-Eingaben über eine Netzwerkfreigabe akzeptieren. Sie können auch als SVG exportieren, um qualitativ hochwertige Thermodrucketiketten auszugeben, oder als Byte-Stream exportieren, um ihn direkt an eine Etikettendrucker-API zu senden.
IronBarcode unterstützt umfangreiche Stilanpassungen, darunter benutzerdefinierte Farben, Randanpassungen , lesbare Textüberlagerungen und, bei QR-Codes, die Einbettung von Logos für markengekennzeichnete mobile Etiketten.

Wie geht man mit Sonderfällen und Fehlern in Scanneranwendungen um?
Welche Fehlerszenarien sollten Entwickler erwarten?
USB-Scanner-Anwendungen versagen auf vorhersehbare Weise. Die häufigsten Probleme und ihre Abhilfemaßnahmen sind:
Scannerverbindung unterbrochen - Wenn ein USB-Scanner ausgesteckt wird, verliert das Tastatur-Wedge-TextBox seine virtuelle Tastatur. Die einfachste Abhilfemaßnahme ist ein periodischer Timer, der _inputBox.Focused überprüft und ihn neu fokussiert, wenn der Scanner noch in der Liste der verbundenen HID-Geräte aufgeführt ist. Bei seriellen Scannern erkennt SerialPort.GetPortNames() eine erneute Verbindung.
Mehrdeutige Barcode-Formate – Einige Produkte tragen Barcodes, die in mehreren Symbologien gültig sind. Eine 12-stellige Zeichenkette ist beispielsweise ein gültiger UPC-A-Code und gleichzeitig ein gültiger Code 128. Die Angabe von ExpectBarcodeTypes in BarcodeReaderOptions beschränkt den Decoder auf die von Ihnen erwarteten Formate und beseitigt Mehrdeutigkeiten. Der IronBarcode Leitfaden zur Fehlerbehebung enthält formatspezifische Erkennungstipps.
Ungültige Formatausnahmen -- Wenn BarcodeWriter.CreateBarcode eine Zeichenkette empfängt, die gegen die Regeln der ausgewählten Kodierung verstößt (z. B. alphabetische Zeichen in einem nur numerischen EAN-13-Feld), wird eine IronBarCode.Exceptions.InvalidBarcodeException-Ausnahme ausgelöst. Durch das Einbetten des Aufrufs in einen try-catch-Block und den Rückgriff auf einen Validierungspfad, der nur Zeichenketten zulässt, kann die Anwendung weiterlaufen.
Kollisionen der Tastenanschlagzeiten – In Umgebungen, in denen die Bediener auch manuell in dasselbe Textfeld tippen, ist der zuvor beschriebene Burst-Timer-Ansatz die primäre Verteidigungsmethode. Eine weitere Schutzmaßnahme ist die Mindestlänge: Die meisten realen Barcodes bestehen aus mindestens 8 Zeichen, daher können kürzere Zeichenketten als Tastatureingabe behandelt werden.
Die Microsoft .NET -Dokumentation zu System.IO.Ports.SerialPort ist hilfreich bei der Fehlersuche in Bezug auf die serielle Scannerverbindung, insbesondere im Zusammenhang mit den Einstellungen ReadTimeout und WriteTimeout. Zur Einhaltung gesetzlicher Vorschriften im Einzelhandel definieren die GS1 General Specifications gültige Wertebereiche für jede Anwendungskennung.
Wie lässt sich die Anwendung auf mobile und Web-Plattformen erweitern?
Das oben gezeigte Scanner-Schnittstellenmuster -- IScannerInput mit BarcodeScanned Ereignis -- abstrahiert die Hardware von der Verarbeitungslogik. Durch den Austausch der Implementierungen kann derselbe Validierungs- und Generierungscode auf verschiedenen Plattformen ausgeführt werden:
- .NET MAUI bietet eine kamerabasierte Scanner-Implementierung für Android- und iOS-Tablets, die als mobile Empfangsstationen verwendet werden.
- Blazor Server unterstützt browserbasiertes Scannen mit JavaScript Kamerazugriff, der in dasselbe
BarcodeScannedEreignis eingespeist wird. - Native Implementierungen für Android und iOS bieten mobilen Entwicklern die Möglichkeit, mit der Kamera zu scannen, wobei im Backend derselbe IronBarcode -Decoder verwendet wird.
Bei Cloud-nativen Architekturen können die Validierungs- und Labelgenerierungsschritte als Azure Functions ausgeführt werden, die durch Warteschlangennachrichten ausgelöst werden, wobei die Desktop-Anwendung lediglich als Eingabegateway für den Scanner fungiert. Diese Trennung ist besonders dann nützlich, wenn die Logik für den Etikettendruck im Rahmen von Compliance-Audits zentralisiert werden muss.
Was sind Ihre nächsten Schritte?
Die Entwicklung einer USB-Barcode-Scanner-Anwendung mit IronBarcode umfasst vier konkrete Schritte: Erfassung der Tastatureingabe mittels Burst-Timing-Erkennung, Validierung des gescannten Werts durch den Decoder von IronBarcode, Generierung von Antwortbezeichnungen im erforderlichen Format und Verarbeitung großer Scanvolumina mit einer parallelen Warteschlange. Jede Phase ist unabhängig und kann isoliert getestet werden.
Erwägen Sie von hier aus, die Anwendung um das Lesen mehrerer Barcodes für Stapelverarbeitungsszenarien, die Optimierung des Bildausschnitts für bildbasierte Eingaben oder die Unterstützung von MSI-Barcodes für ältere Lagertechnik zu erweitern. Die IronBarcode Dokumentation umfasst alle unterstützten Formate und erweiterte Konfigurationsoptionen für das Lesegerät.
Starten Sie eine kostenlose Testphase , um einen Entwicklerlizenzschlüssel zu erhalten und IronBarcode noch heute in Ihre Scan-Anwendung zu integrieren.
Häufig gestellte Fragen
Was ist IronBarcode und wie hängt es mit USB-Barcodescannern zusammen?
IronBarcode ist eine Bibliothek, die es Entwicklern ermöglicht, robuste C#-Anwendungen für USB-Barcodescanning zu erstellen. Sie bietet Funktionen wie Barcode-Validierung, Datenextraktion und Barcode-Generierung.
Kann IronBarcode Barcodedaten von einem USB-Scanner validieren?
Ja, IronBarcode kann von einem USB-Scanner erfasste Barcodedaten validieren und so die Datenintegrität und -genauigkeit in Ihren C#-Anwendungen sicherstellen.
Wie behandelt IronBarcode die Barcode-Generierung?
IronBarcode kann neue Barcodes "on-the-fly" generieren und ermöglicht es Entwicklern, Barcodes einfach innerhalb ihrer C#-Anwendungen zu erstellen und zu drucken.
Gibt es eine Unterstützung für die Fehlerbehandlung in IronBarcode für USB-Barcodescanning?
Ja, IronBarcode beinhaltet eine umfassende Fehlerbehandlung, um häufige Probleme zu bewältigen, die während des USB-Barcodescannings und der -verarbeitung auftreten können.
Welche Arten von Barcodes können mit IronBarcode gescannt werden?
IronBarcode unterstützt das Scannen einer Vielzahl von Barcode-Symbologien, einschließlich QR-Codes, UPC, Code 39 und mehr, was es vielseitig für verschiedene Anwendungen macht.
Kann IronBarcode strukturierte Informationen aus gescannten Barcodes extrahieren?
Ja, IronBarcode kann strukturierte Informationen aus gescannten Barcodes extrahieren, was eine effiziente Datenverarbeitung und -verwaltung unterstützt.
Wie kann ich mit dem Aufbau einer USB-Barcodescanner-Anwendung in C# beginnen?
Um mit dem Aufbau einer USB-Barcodescanner-Anwendung in C# zu beginnen, können Sie IronBarcode zusammen mit den bereitgestellten Codebeispielen und der Dokumentation verwenden, um Ihren Entwicklungsprozess zu leiten.




