Thursday, January 28, 2016

C#: Barcode Scanning with Windows Phone 8

While a little off-topic, this post will focus on how to implement barcode scanning within a C# Windows Phone application.  Several times in the past year I have needed this functionality, so rather than continue to re-open my past Visual Studio project files, I'll instead share what I've found and how to make it work.  This article will provide a step-by-step approach to adding barcode functionality into your C# Windows Phone application and can be modified somewhat if needed for other Windows Platforms.
For those interested, I've provided a full sample project here for your reference.

Step 0: Create or Open your C# Windows Phone Project

This article assumes the reader already has a base understanding of using Visual Studio and has already created a Windows Phone 8 or 8.1 project inside of Visual Studio (any edition). 

Step 1: Add ZXing to your Project

Thanks to the makers of the ZXing library, the open source community has shared an amazing set of utility code to read and parse image data for barcodes.  This solution makes use of the ZXing port over to .NET called
Additionally, the community has made their library available through NuGet, which makes adding it to your project a trivial matter.  To use the NuGet package, open the package manager from the Project menu as shown in the following:

Once open, search for the package, and add it by clicking the checkbox associated with the platform being supported (WP8-Barcode in this example).

Once completed, this will install the required package into your project and add all required references. 

Step 1 [Shortcut] – Install from Package Manager

Many of the more seasoned developers will know, you can simply add the project to your file by using the package manager command prompt instead. 

Step 2 – Add Library Includes (‘using’) References to Page

In order to leverage the camera, image manipulation and ZXing libraries in your code, for ease of use, you’ll want to add references to the libraries to the top of your source code.  The following will be required:
using Microsoft.Devices;
using ZXing;
using System.Windows.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Input;

Step 3 - Create XAML Screen as a Viewfinder

Before diving into the c# event handlers and such, lets setup a simple viewfinder where we can show the camera contents, and for this example, simply display whatever barcode we've processed/read. To do this, something similar to the following XAML would be required.

    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="200"/>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="WP8 Barcode" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="scan barcode" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Canvas x:Name="viewfinderCanvas" Margin="0,0,0,10">
                <!--Camera viewfinder -->

                    <VideoBrush x:Name="viewfinderBrush">
                    Text="[   ]" 
                    FontSize="40" Visibility="Collapsed"/>

                <TextBlock Canvas.Left="100" TextWrapping="Wrap" Text="Tap to read the Barcode" Canvas.Top="200" Width="233" FontFamily="Segoe UI"/>

        <StackPanel Grid.Row="2" Margin="20, 0">
            <TextBlock Text="Barcode Type:"/>
            <TextBlock x:Name="tbBarcodeType" FontWeight="ExtraBold" Text="[Please Scan]"/>
            <TextBlock Text="Barcode Data:"/>
            <TextBlock x:Name="tbBarcodeData" FontWeight="ExtraBold" TextWrapping="Wrap" Text="[Please Scan]"/>



Step 4 - Define the Private Local Variables Required

Several of the core objects we'll be using will have a scope beyond the method being executed, therefore we will need to define some private variables to hold pointers to these objects.
//private locals
private PhotoCamera _phoneCamera;
private IBarcodeReader _barcodeReader;
private DispatcherTimer _scanTimer;
private WriteableBitmap _previewBuffer;

Step 5 - Initialize the Camera and Add Event Handlers

This can be done anywhere in your code (for example on a button press), but for this example, I've added it to the OnNavigatedTo method.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            // Initialize the camera object
            _phoneCamera = new Microsoft.Devices.PhotoCamera(CameraType.Primary);

            //event callbacks defined
            _phoneCamera.Initialized += new EventHandler(cam_Initialized);
            _phoneCamera.AutoFocusCompleted += _phoneCamera_AutoFocusCompleted;
            CameraButtons.ShutterKeyHalfPressed += CameraButtons_ShutterKeyHalfPressed;
            viewfinderCanvas.Tap += new EventHandler(focus_Tapped);

            //Display the camera feed in the UI

            // This timer will be used to scan the camera buffer every 250ms and scan for any barcodes
            _scanTimer = new DispatcherTimer();
            _scanTimer.Interval = TimeSpan.FromMilliseconds(250);
            _scanTimer.Tick += (o, arg) => ScanForBarcode();

As shown above, the device's camera object needs to be initialized, callbacks assigned to the event methods (see later steps for each of these callback definitions), and a timer initiated to periodically get whatever is in the camera buffer. This could also be changed to only grab the camera buffer on an event of some kind (e.g. camera button pressed, screen tapped, etc.) but for this example, it has been just established as a periodic 250ms.

Step 6 - Include an Autofocus Completed Event Handler

The viewfinder in this example includes a set of brackets '[ ]' in the UI to allow the user to define the point of focus when they tap the screen. Once the autofocus has been completed, this callback method is triggered to simply show where the brackets should appear on the page.
void _phoneCamera_AutoFocusCompleted(object sender, CameraOperationCompletedEventArgs e)
            Deployment.Current.Dispatcher.BeginInvoke(delegate ()
                focusBrackets.Visibility = Visibility.Collapsed;

Step 7 - Include a Screen Tap Event Handler

To support focusing on a single point within the virtual viewfinder, we have to add an event handler for the screen tap event (see OnNavigatedTo method above for where the event is assigned).
void focus_Tapped(object sender, System.Windows.Input.GestureEventArgs e)
                if (_phoneCamera != null)
                    if (_phoneCamera.IsFocusAtPointSupported == true)
                        // Determine the location of the tap.
                        Point tapLocation = e.GetPosition(viewfinderCanvas);

                        // Position the focus brackets with the estimated offsets.
                        focusBrackets.SetValue(Canvas.LeftProperty, tapLocation.X - 30);
                        focusBrackets.SetValue(Canvas.TopProperty, tapLocation.Y - 28);

                        // Determine the focus point.
                        double focusXPercentage = tapLocation.X / viewfinderCanvas.ActualWidth;
                        double focusYPercentage = tapLocation.Y / viewfinderCanvas.ActualHeight;

                        // Show the focus brackets and focus at point.
                        focusBrackets.Visibility = Visibility.Visible;
                        _phoneCamera.FocusAtPoint(focusXPercentage, focusYPercentage);
            catch (Exception ex)
                _phoneCamera.Initialized += new EventHandler(cam_Initialized);

Step 8 - Include a Half-Press Camera Button Handler

As with the above, if our device supports half-presses from the camera button, use it to trigger the camera's autofocus.
void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)

Step 9 - Include some final Configuration in the Camera Initialized Event

Some final configuration can be added once we know the camera is initialized, and we can begin our camera scan timer and start attempting reads. Optionally, this timer can be removed and only await a camera press or screen tap.
void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)

Step 10 - Include Scan for Barcode Logic

We add this method to save temporary images to the camera buffer and we make calls to ZXing to decode the content within this buffer.
private void ScanForBarcode()
            //grab a camera snapshot

            //scan the captured snapshot for barcodes
            //if a barcode is found, the ResultFound event will fire

Step 11 - Add a Barcode Found Callback

This method is called whenever ZXing yields a result from the decoding attempt. This is where we can add logic to parse the barcode data, save it in memory, or even navigate away from the screen if we just wanted to scan a single barcode.
void _bcReader_ResultFound(Result obj)
            // If a new barcode is found, vibrate the device and display the barcode details in the UI
            if (!obj.Text.Equals(tbBarcodeData.Text))
                tbBarcodeType.Text = obj.BarcodeFormat.ToString();
                tbBarcodeData.Text = obj.Text;
                //do something real with the scan (e.g. persist it to a the State or ViewModel object before you leave the page)
                //PhoneApplicationService.Current.State["Text"] = obj.Text;

                //Navigate to some other page if you're done scanning
                //NavigationService.Navigate(new Uri("/PageYouWantToGetResult.xaml", UriKind.Relative));


Step 12 - Include Cleanup Logic

With camera and device access on Windows Phone, it is ABSOLUTELY CRITICAL that we cleanup our variables once we're done with them. If omitted, it is possible for your camera to keep on capturing and processing data, leaving flashes flashing, and simply crash your application. We've chosen to include all the cleanup code in OnNavigatedFrom method, or is automatically called by the system when a user navigates away from this page.
protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
            //we're navigating away from this page, be sure to run this cleanup or you'll have issues

            if (_phoneCamera != null)
                // Cleanup
                _phoneCamera.Initialized -= cam_Initialized;
                CameraButtons.ShutterKeyHalfPressed -= CameraButtons_ShutterKeyHalfPressed;

Step 13 - Specify Application Capabilities

With Windows Phone and Windows Store applications, it is mandatory that you specify what capabilities your application requires in order to be used within the Application Manifest File (WMAppManifest.xml). If this isn't set, your application will not be granted access to the device/sensor required, and will therefore keep crashing when attempting these unpermitted steps. For this application, we need to grant rights for the application to use the camera and, just to be safe, the photo library, as shown in the following.

Step 14 - Specify Application Requirements

Additionally, in the same file (WMAppManifest.xml), there is also a section for specifying the minimum requirements for the device running your app. In this case, we'll of courses require a camera, so you'll want to flag this as a requirement for your application as shown in the following.

Step 15 - Update Packaging with Capabilities for the Storefront

While not technically mandatory, it is considered good policy to update your application's packaging to ensure the Windows Store storefront page conveys your application requirements properly. This is done by updating the Package.appmanifest file within Visual Studio. For this simple application, I've marked that we're accessing the "webcam" and "pictures library" as they seem to be the best fit. This is also where you will want to version your application so that the package file automatically updates the storefront when you upload your package to the store.

Final - Compile and Run

If all the above is correct, you should be able to build and run your application. Since you'll be using the camera on a device, I'd recommend targeting your developer device (and not the emulator), so you can scan some web-generated QR Codes or other Bar Code Types. Any troubles, try downloading the sample application as a whole and running the sample package to see if you are missing any SDK's. The sample was built using the free Visual Studio 15 Community Edition with .NET and WindowsMobile 8 SDK's.

Wednesday, October 2, 2013

jQuery: NIEM Parsing with jQuery

This series of articles will look at how to leverage jQuery to access and manipulate NIEM-conformant XML payloads. The first article looks simply at the capability to access, parse and read the data contained in a nc:AddressFullText element, strip whitespace from it, and place it in a text area on a web page. Later articles will explain how to handle multiple occurrences of a single element and eventually map the address on a webpage.
jQuery is a powerful scripting tool used by many modern developers in creating and processing web pages. We will be using it as a client-side script where the user's browser is working on an XML stream directly without doing work on a server. This is one approach to leveraging the power of a client's own browser in the current "AJAX" development stagey.
The first step in leveraging jQuery is actually including the appropriate library on your web-page. There are both compressed and uncompressed versions of this library available on and in many cases you can simply link to a hosted copy of the library on the web. For this exercise, let's assume we have a copy of the library hosted on the same server (and in the same directory) as the html page we're writing. In this case, we will include the script by using the following:
<!-- jQuery Include (change to match the file name and location where you have the jQuery library stored) -->
<script src="jquery-1.10.2.js"></script>
With the library included on our HTML page, we can access all the features available to us within our on-page JavaScript. In order to use a stream of XML data, we'll need to first parse it. in jQuery we simply use the $.parseXML(string) command. This will return for us a parsed XML document. As we don't want our users to receive unhandled exceptions, and there is never a guarantee the XML we process is without error, we want to be sure to use try/catch when parsing our file. Here is what the snippet of parsing would look like:
//the try & catch block support for .parseXML() requies jQuery 1.9 or newer!
       var xmlDoc = $.parseXML(xml);
       var $xml = $(xmlDoc);
     } catch (err) {
       alert("Error parsing XML!  Likely invalid XML or undefined namespace prefix.");
Once we have successfully parsed the XML document, we can access portions of the document using a number of jQuery-supported methods. One of the simplest methods (and the one we will use today) is the xmlDocument.find('pattern') method. It simply returns an element [array] for all the elements it finds that match the pattern passed into the function. For example, if we want to "find" all of the elements called PersonName, we would simply pass it 'PersonName'. Here, we will assume we're working with nc:Address elements that contain plain text addresses and our expanded code will look something like this:
$address = $xml.find("nc\\:AddressFullText, AddressFullText");

You will notice we passed in two parameters. This is to work around a compatibility issue between Web-Kit-Based Browsers (Chrome, Firefox, Safari, etc.) and Microsoft Internet Explorer (IE). IE allows us to use an escape-sequenced colon to define our element prefix (\\:), however the Web-Kit browsers do not. By passing it both a prefixed and simple element name, both browser types will accept and process the find properly.
Since we are processing a plain text field, we will likely have some extra whitespace (spaces and line-feeds) that we don't want. We can simply use a string.replace('pattern') with a regex to clear out what we don't want and save the text value contained in our element by using the .text() method as shown in the following.
//Clear Whitespaces and save text value of the element in a string variable
textAddress = $address.text().replace(/^(\s*)|(\s*)$/g, '').replace(/\s+/g, ' ');
Once we have the value saved in a variable, we can now use it in any way we want directly in our script. The following is the full HTML and JavaScript/jQuery code for this example including a text field for entering NIEM-conformant XML and a text field for the parsed data.
<!DOCTYPE html>
<html xmlns="">
    <title>nc:Address jQuery Parse Example</title>

    <!-- jQuery Include (change to match the file name and location where you have the jQuery library stored) -->
    <script src="jquery-1.10.2.js"></script> 

    <!-- On Page JavaScript -->
        function resolveAddress() {
            var textAddress;
            var $address;
            var xml = textField.value;

            //the try & catch block support for .parseXML() requies jQuery 1.9 or newer!
                var xmlDoc = $.parseXML(xml);
                var $xml = $(xmlDoc);
            } catch (err) {
                alert("Error parsing XML!  Likely invalid XML or undefined namespace prefix.");

            //jQuery .find()
            //find any and all values stored in the (possibly repeating) element nc:AddressFullText
            //The following returns an ELEMENT and requires we use .text() to access the return value
            $address = $xml.find("nc\\:AddressFullText, AddressFullText");
            //Clear Whitespaces
            textAddress = $address.text().replace(/^(\s*)|(\s*)$/g, '').replace(/\s+/g, ' ');
            //Output Value
            textFindOutput.value = textAddress;


    <p style="font-family:'Segoe UI'">
        Enter or paste in a valid nc:Address block and click on the "Parse Data" button.

    <textarea id="textField" style="width:100%;height:100px">
<myExchange xmlns:nc=''>
        One Microsoft Way
        Redmond, WA 98052

    <p><button id="go" onclick="resolveAddress()">Parse Data</button></p>
        <p style="font-family:'Segoe UI'">jQuery .find("nc\\:AddressFullText") using .text() to access the <u>text</u> found.</p>
        <textarea id="textFindOutput" style="width:100%;height:100px"></textarea>


Additionally, you can simply access a sample of this code working here.