How to Easily set up a Textbox to Accept Scans from Motorola/Symbol Barcode Scanners in Windows CE / .NET CF Projects






4.94/5 (10 votes)
Step-by-step guide to add barcode-scanning capability to a Windows CE / Compact Framework app
Barcode Scanning (I couldn't think of a cleverer subheading)
So you wanna (more likely, need to) input some scanned data into a textbox on a form. It's not all that rocket-sciencey. Here are the steps:
First, reference the following two DLLs in your project:
Symbol
Symbol.Barcode
...which DLLs should be included along with your device; otherwise, they should be available from the Motorola site here or over yonder, although I couldn't find them (I didn't search all that hard since I already had about a gazillion copies of them on my PC).
Add these DLLs to the folder on your handheld device where your app resides, too.
Note: This code has been adapted from Motorola's CS_ScanSample1
sample project; basically, I de-nerdified some of the names of objects and methods (or super-nerdified - YMMV) and wrote the scanned value into a textbox. Also, instead of responding to a button click to start the scanning (as the demo app does), I used the textBox
's GotFocus()
event. And to stop the scanning, I set focus to the next control on the form after the data has been written to the textbox
. This, in turn, calls the textbox
's LostFocus()
method for some cleanup code.
So, you can use this code as-is, with the exception that you will want to rename the textbox that will receive the scanned value ("textBoxUPC_PLU
") and the next control where focus is set ("textBoxPackSize
") to controls that make sense in your case.
The Code (I'm still suffering from a Brain Freeze, Catchy-Subheading-Wise)
Now for the code; add these members to your form:
private Symbol.Barcode.Reader barcodeReader;
private Symbol.Barcode.ReaderData barcodeReaderData;
private EventHandler barcodeEventHandler;
Then add this code:
private bool InitReader()
{
// If reader is already present then retreat
if (this.barcodeReader != null)
{
return false;
}
// Create new reader, first available reader will be used.
this.barcodeReader = new Symbol.Barcode.Reader();
// Create reader data
this.barcodeReaderData = new Symbol.Barcode.ReaderData(
Symbol.Barcode.ReaderDataTypes.Text,
Symbol.Barcode.ReaderDataLengths.MaximumLabel);
// Create event handler delegate
this.barcodeEventHandler = this.BarcodeReader_ReadNotify;
// Enable reader, with wait cursor
this.barcodeReader.Actions.Enable();
this.barcodeReader.Parameters.Feedback.Success.BeepTime = 0;
this.barcodeReader.Parameters.Feedback.Success.WaveFile = "\\windows\\alarm3.wav";
// Attach to activate and deactivate events
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
return true;
}
private void StartRead()
{
// If we have both a reader and a reader data
if ((this.barcodeReader != null) && (this.barcodeReaderData != null))
{
// Submit a read -- I sometimes got an exception about a read already being pending here, so:
if (this.barcodeReaderData.IsPending) return;
this.barcodeReader.ReadNotify += this.barcodeEventHandler;
this.barcodeReader.Actions.Read(this.barcodeReaderData);
}
}
private void BarcodeReader_ReadNotify(object sender, EventArgs e)
{
Symbol.Barcode.ReaderData TheReaderData = this.barcodeReader.GetNextReaderData();
if (TheReaderData.Result == Symbol.Results.SUCCESS)
{
// Handle the data from this read
this.HandleData(TheReaderData);
// Start the next read
this.StartRead();
}
}
private void ReaderForm_Activated(object sender, EventArgs e)
{
// If there are no reads pending on barcodeReader start a new read
if (!this.barcodeReaderData.IsPending)
{
this.StartRead();
}
}
private void ReaderForm_Deactivate(object sender, EventArgs e)
{
this.StopRead();
}
private void StopRead()
{
// If we have a reader
if (this.barcodeReader != null)
{
// Flush (Cancel all pending reads)
this.barcodeReader.ReadNotify -= this.barcodeEventHandler;
this.barcodeReader.Actions.Flush();
}
}
private void DisposeBarcodeReaderAndData()
{
// If we have a reader
if (this.barcodeReader != null)
{
// Disable the reader
this.barcodeReader.Actions.Disable();
// Free it up
this.barcodeReader.Dispose();
// Indicate we no longer have one
this.barcodeReader = null;
}
// If we have a reader data
if (this.barcodeReaderData != null)
{
// Free it up
this.barcodeReaderData.Dispose();
// Indicate we no longer have one
this.barcodeReaderData = null;
}
}
private void HandleData(Symbol.Barcode.ReaderData readerData)
{
textBoxUPC_PLU.Text = readerData.Text;
// now move off of it to next non-read-only textBox
textBoxPackSize.Focus();
}
In HandleData()
, replace "textBoxUPC_PLU
" with the name you've given your TextBox
control. Similarly, replace "textBoxPackSize
" with the name of the next control you want to get the focus after scanning is complete.
Note: In my case, the code in DisposeBarcodeReaderAndData()
was actually causing NREs; in at least one scenario, I had to comment out that code. YCEMV (Your Coding Experience May Vary).
Delayed Dispatch from the Trenches
I find that this is helpful/necessary when closing a form that does barcode scanning:
private void FrmDelivery_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.barcodeReader.Actions.Disable();
}
This seems to allow subsequent forms to use barcode scanning (see my multiple-times-updated question here for the gory details of the problems I was having in attempting to do so).
More Crash Prevention
It turns out that calling barcodeReader.Actions.Disable() crashes the app if no scan was done. To ameliorate, adjudicate, and alleviate (but not anthropomorphize) this, we have to keep track of whether a scan was done.
So, being the neanderthalic brutish modified Luddite that I am, I simply added a bool to the form like so:
private bool scanWasDone;
...and then set that to true in the InitReader event (several events are fired when a scan is done, but this appears to be the first and functions (no pun intended) as good as any of them for this purpose):
private bool InitReader()
{
scanWasDone = true;
. . .
Finally, in the form's Closing event, only call Actions.Disable if a scan was done:
private void frmVerify_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Calling disable is necessary if a scan was done, but it crashes the app if no scan was done
if (scanWasDone)
{
this.barcodeReader.Actions.Disable();
}
}
Kudos and Cavalier Caveats
The above is pretty much the same as the Symbol sample code, except that I renamed things like "myEventHandler
" to "barcodeEventHandler
". I don't know why, but prepending "My
" to software objects, methods, &c has always irked me (admittedly, way more than it should) and sounds to me like baby talk (goo goo, ga ga, etc.). I also changed the method name "TermReader
" (which sounds like somebody is going to clamber up on a soapbox and regale an unsuspecting captive audience with the reading aloud of their term paper) to "DisposeBarcodeReaderAndData
". Maybe you prefer the former; of course, you can name it "WhichIsYourFavoriteTrio_TheThreeMusketeersOrTheThreeLittlePigs
" if you want to (but don't be a Dumas -- only do this if you are absolutely certain that those who might maintain your app in the future don't know where you live).
Notice, also, though, that I did add some my-form-specific code to the HandleData()
method:
textBoxUPC_PLU.Text = readerData.Text;
// now move off of it to the next non-read-only textBox
textBoxPackSize.Focus();
I assigned the read data to the texbox
set up to be responsive to the barcode scanner, and then I moved the cursor to the next control (which causes the LostFocus()
/ cleanup code to run).
Now that you've got that code, you can add the handler code to the textBox
that makes this the "barcode-scan-responsive" control; first, there's the GotFocus()
event:
private void textBoxUPC_PLU_GotFocus(object sender, EventArgs e)
{
if (this.InitReader())
{
this.StartRead();
}
}
...and next/finally is the textBox
's LostFocus()
event, which will do the requisite cleanup:
private void textBoxUPC_PLU_LostFocus(object sender, EventArgs e)
{
this.DisposeBarcodeReaderAndData();
}
Und Damit Basta! (That's not Cussing, it's German)
Aha! Voila! Eureka! Woo-hoo! Yee-haw! Great Day in the Mornin'! (it works). While in the textBox
that has been set up to receive scanning (textBoxUPC_PLU
), if I scan an item, its value is entered into the textBox
, and focus is then moved to the next textBox
.
This was tested on a Motorola 3190 and a Windows CE project with the affiliated stripped-down version of .NET 3.5 (Compact Framework), using Visual Studio 2008. I reckon the code would also work in even feebler versions of .NET / CE / CF, and doubtless on other Motorola/Symbol devices.