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:
...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 (this.barcodeReader != null)
{
return false;
}
this.barcodeReader = new Symbol.Barcode.Reader();
this.barcodeReaderData = new Symbol.Barcode.ReaderData(
Symbol.Barcode.ReaderDataTypes.Text,
Symbol.Barcode.ReaderDataLengths.MaximumLabel);
this.barcodeEventHandler = this.BarcodeReader_ReadNotify;
this.barcodeReader.Actions.Enable();
this.barcodeReader.Parameters.Feedback.Success.BeepTime = 0;
this.barcodeReader.Parameters.Feedback.Success.WaveFile = "\\windows\\alarm3.wav";
this.Activated += ReaderForm_Activated;
this.Deactivate += ReaderForm_Deactivate;
return true;
}
private void StartRead()
{
if ((this.barcodeReader != null) && (this.barcodeReaderData != null))
{
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)
{
this.HandleData(TheReaderData);
this.StartRead();
}
}
private void ReaderForm_Activated(object sender, EventArgs e)
{
if (!this.barcodeReaderData.IsPending)
{
this.StartRead();
}
}
private void ReaderForm_Deactivate(object sender, EventArgs e)
{
this.StopRead();
}
private void StopRead()
{
if (this.barcodeReader != null)
{
this.barcodeReader.ReadNotify -= this.barcodeEventHandler;
this.barcodeReader.Actions.Flush();
}
}
private void DisposeBarcodeReaderAndData()
{
if (this.barcodeReader != null)
{
this.barcodeReader.Actions.Disable();
this.barcodeReader.Dispose();
this.barcodeReader = null;
}
if (this.barcodeReaderData != null)
{
this.barcodeReaderData.Dispose();
this.barcodeReaderData = null;
}
}
private void HandleData(Symbol.Barcode.ReaderData readerData)
{
textBoxUPC_PLU.Text = readerData.Text;
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)
{
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;
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.