Archive

Posts Tagged ‘Windows Phone 7’

Silverlight for Windows Phone 7: How to use ZXing 7.1 in Silverlight

November 22nd, 2011 Admin 16 comments

    ZXing is an open source library for processing of multi-format 1D/2D barcode images. Using a built-in camera on your mobile phone you can scan a barcode (i.e. make a picture containing the barcode) and decode it by exploiting ZXing library. As the result you may have a recognized and decoded string value of barcode. The library supports such formats as traditional UPC-A and UPC-E, EAN-8 and EAN-13, trendy QR Code and etc. The library initially is implemented in Java, but there is a port to C#. However, if you decide to use this port in Silverlight Windows Phone 7 project, you’ll run into some problems with compatibility as Silverlight provides a “limited” C#. To be more specific, the C# port of ZXing actively utilizes such non-generic collections as Hashtable and ArrayList from System.Collections namespace, but almost everything under this namespace was completely removed from Silverlight. For details, please read the following article – Non-Generic Collections to be Removed from Silverlight. Hashtable and ArrayList can be replaced with System.Collections.Generic.Dictionary<Object, Object> and System.Collections.Generic.List<Object> respectively. Instances are received as System.Collections.ArrayList.Synchronized() can be smoothly turned into usual instances, that are not thread safe, because multithreading isn’t used in the library. If it’s necessary to provide thread safety, it can be done outside the library at the stage of instantiating of and accessing to the barcode readers contained in ZXing library. Just follow the rule – each thread must allocate its own object.

Furthermore, the ZXing C# port uses Color, Rectangle and Bitmap classes from System.Drawing, which is unavailable in Silverlight as well. As the replacement we can consider System.Windows.Media.Color, System.Windows.Rect and System.Windows.Media.Imaging.WriteableBitmap respectively, but they aren’t absolutely compatible with the preceding ones and some kind of adjustment code is required.

System.SerializableAttribute isn’t accessible too. We can just get rid of it. A number of other small changes are required as well.

As the result, I made a Silverlight port of ZXing 7.1 from C# port. You can download it here or here. Where the original code was replaced, I left commentaries kind of “here was .net follower” :)

A few words of how to use it. In my application I try reading and decoding barcodes of UPC-A and UPC-E formats. For my needs I implemented a very simple wrapper around ZXing libraryBarcodeHelper, probably, it may be useful for somebody else (the helper is in downloadable solution). The wrapper is shown below. In the method TryToRecognizeBarcode you can see how interaction with ZXing is usually being put into practice.
Update: other methods, TryToRecognizeQRcode and TryToRecognizeDataMatrix were added to the BarcodeHelper. They allow to recognize QR and Data Matrix codes, respectively.

using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;

using com.google.zxing;

namespace Helpers
{
    public static class BarcodeHelper
    {
        public static bool TryToRecognizeBarcode(WriteableBitmap wb, out string barCode)
        {
            // set some recognition settings
            var zxhints = new Dictionary<object, object>()
                {
                    { DecodeHintType.TRY_HARDER, true },
                    { DecodeHintType.POSSIBLE_FORMATS, new List<Object>() { BarcodeFormat.UPC_A, BarcodeFormat.UPC_E } }
                };

            // create reader instance
            var reader = new com.google.zxing.oned.MultiFormatUPCEANReader(zxhints);
            return TryToRecognize(wb, reader, zxhints, out barCode);
        }

        public static bool TryToRecognizeQRcode(WriteableBitmap wb, out string qrCode)
        {
            // create reader instance
            var reader = new com.google.zxing.qrcode.QRCodeReader();
            return TryToRecognize(wb, reader, null, out qrCode);
        }

        public static bool TryToRecognizeDataMatrix(WriteableBitmap wb, out string dtm)
        {
            // create reader instance
            var reader = new com.google.zxing.datamatrix.DataMatrixReader();
            return TryToRecognize(wb, reader, null, out dtm);
        }

        private static bool TryToRecognize(WriteableBitmap wb, Reader reader, Dictionary<object, object> zxhints, out string output)
        {
            bool res = false;
            output = null;
            try
            {
                var luminiance = new RGBLuminanceSource(wb, wb.PixelWidth, wb.PixelHeight);
                var binarizer  = new com.google.zxing.common.HybridBinarizer(luminiance);
                var binBitmap  = new com.google.zxing.BinaryBitmap(binarizer);

                // recognize
                var results = reader.decode(binBitmap, zxhints); // exception will be thrown if reader cannot decode image.

                output = results.Text;
                res = true;
            }
            catch (Exception ex)
            {
            }
            return res;
        }
    }
}

Below is the sample code of usage taken from TestApplication (see downloadable solution):

WriteableBitmap wbmp = new WriteableBitmap(barcodeSample.Source as BitmapImage);
string recognizedOutput = string.Empty;
if (BarcodeHelper.TryToRecognizeBarcode(wbmp, out recognizedOutput))
// if (BarcodeHelper.TryToRecognizeQRcode(wbmp, out recognizedOutput))
// if (BarcodeHelper.TryToRecognizeDataMatrix(wbmp, out recognizedOutput))
    resultTexBlock.Text = recognizedOutput;
else
    resultTexBlock.Text = "Unrecognizable barcode!";

Hint: if the recognition failed on an image with a high resolution and, apparently, a big size, try reducing the image size in two times step by step until the image is recognized.

The following part of another simple test application demonstrates how to use camera to make picture containing barcode and recognize it then. You can find this small application in downloadable solution as well.

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Tasks;
using System.Windows.Media.Imaging;
using System.IO;
using Helpers;

namespace WindowsPhoneApplication2
{
    public partial class MainPage : PhoneApplicationPage
    {
        private CameraCaptureTask camera = new CameraCaptureTask();

        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            button1.IsEnabled = false;            

            camera.Completed += new EventHandler<PhotoResult>(camera_Completed);
            camera.Show();
        }

        void camera_Completed(object sender, PhotoResult e)
        {
            camera.Completed -= new EventHandler<PhotoResult>(camera_Completed);

            if (e.TaskResult == TaskResult.OK)
            {
                BitmapImage bmp = new BitmapImage();
                bmp.CreateOptions = BitmapCreateOptions.None; //Don't delay creation
                bmp.SetSource(e.ChosenPhoto);

                resultTexBlock.Text = string.Empty;

                WriteableBitmap wbmp = new WriteableBitmap(bmp);
                string recognizedBarcode = string.Empty;
                if (BarcodeHelper.TryToRecognizeBarcode(wbmp, out recognizedBarcode))
                    resultTexBlock.Text = recognizedBarcode;
                else
                    resultTexBlock.Text = "Unrecognizable barcode!";
            }            

            button1.IsEnabled = true;
        }
    }
}

If you find a bug, please, leave an appropriate comment here and the issue will be fixed in a timely manner.

Download ZXing7_1_Port.zip (Visual Studio 2010 Solution)

ps There is an alternative – Windows Phone 7 Silverlight ZXing Barcode Scanning Library, but, as I see, the version of ZXing they use isn’t up-to-date.

Related posts:

Silverlight for Windows Phone 7: How to subclass PhoneApplicationPage

August 17th, 2011 Admin No comments

     The first step is adding a cs-file with the class derived from PhoneApplicationPage:

using System;
using Microsoft.Phone.Controls;

namespace WindowsPhoneApplication1
{
    public class MyPhoneAppPage : PhoneApplicationPage
    {
        // one of your custom properties
        protected bool IsUIThread
        {
            get { return Dispatcher.CheckAccess(); }
        }
    }
}

The second step is turning the target page into a descendant of MyPhoneAppPage. To accomplish that, we need to replace all the mentions of the standard PhoneApplicationPage in the xaml-file and code-behind file with MyPhoneAppPage:

<my:MyPhoneAppPage
    x:Class="WindowsPhoneApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:my="clr-namespace:WindowsPhoneApplication1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

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

Do not forget to add the xmlns:my attribute, which contains the namespace where MyPhoneAppPage is defined, to the root tag.

Sample of usage:

using System;
using Microsoft.Phone.Controls;

namespace WindowsPhoneApplication1
{
    public partial class MainPage : MyPhoneAppPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            bool parentProp = IsUIThread; // usage of the ancestor property
        }
    }
}

That’s all. Compile and enjoy. Sometimes the designer highlights xaml with a blue wavy line, as if it was a wrong markup. Don’t worry, all the “errors” disappear during the compilation.

Related posts:

Silverlight for Windows Phone 7: How to check if the current thread is UI one

July 19th, 2011 Admin 2 comments

     If in your wp7 application you are planning to use background threads for some long operations, you likely need from time to time to update controls to reflect state and/or result of operations. Any update has to be done in the UI thread, in which all controls are created. Being in another thread we can use object Dispatcher to invoke a method inside the UI thread:

Dispatcher.BeginInvoke(delegate() { /* update controls */ });

Before invoking a method, it’s a good practice to check whether the current calling thread is different from UI thread. And if the current thread is the UI thread, we can update controls directly, not using Dispatcher. To examine the current thread, there is a method CheckAccess() of Dispatcher object. It returns true if the calling thread is the UI thread, otherwise, false. Taking this fact into account, a typical way to update control is:

public void UpdateSomeTextBox(string text)
{
    if (Dispatcher.CheckAccess()) // if it's UI thread, just set the new text directly
        someTextBox.Text = text;
    else // otherwise, invoke UpdateSomeTextBox in UI thread
        Dispatcher.BeginInvoke(delegate()
        {
            UpdateSomeTextBox(text);
        });
}

Interestingly enough that the method Dispatcher.CheckAccess() is invisible for Intellisense, because, for some unknown reason, it has been marked with a [EditorBrowsable(EditorBrowsableState.Never)] attribute. It looks like Microsoft doesn’t want developers to use CheckAccess. But does an alternative exist? Let’s try to find it. First of all, let’s take a look at this method through the Reflector:

[EditorBrowsable(EditorBrowsableState.Never)]
public bool CheckAccess()
{
    return (NativeHost.Current.UIThreadID == Thread.CurrentThread.ManagedThreadId);
}

It just compares an identifier of UI thread with an identifier of the current thread. NativeHost is an internal class, therefore we can’t get NativeHost.Current.UIThreadID outside of a dll where property declared. How else can we get the identifier of UI thread? As we know all controls, including page, are created inside UI thread. It means that inside a page constructor the property Thread.CurrentThread.ManagedThreadId is the required UI thread identifier. So, we need take this identifier and preserve to use later. The following example demonstrates how it could look like:

using System;
using Microsoft.Phone.Controls;

namespace WindowsPhoneApplication1
{
    public partial class MainPage : PhoneApplicationPage
    {
        private int _uiThreadID = -1;

        private bool IsUIThread
        {
            get { return _uiThreadID == System.Threading.Thread.CurrentThread.ManagedThreadId; }
        }

        // Constructor
        public MainPage()
        {
	    // preserve UI thread id
            _uiThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
            InitializeComponent();
        }

        public void UpdateSomeTextBox(string text)
        {
            if (IsUIThread)  // if it's UI thread, just set the new text directly
                someTextBox.Text = text;
            else   // otherwise, invoke UpdateSomeTextBox in UI thread
                Dispatcher.BeginInvoke(delegate()
                {
                    UpdateSomeTextBox(text);
                });
        }
    }
}

Thanks!

Related posts:

Silverlight for Windows Phone 7: Change panorama control’s title

June 29th, 2011 Admin No comments

     You can easily change the look of Panorama-control title by applying TitleTemplate:

<controls:Panorama Title="my pano">
    <controls:Panorama.TitleTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" FontSize="100" Margin="0,50,0,0" />
        </DataTemplate>
    </controls:Panorama.TitleTemplate>
</controls:Panorama>

This piece of xaml allows to get the title smaller.

Panorama Title before

Before

After

Pay attention to Margin-attribute stated above. The default attributes for Panorama title is

Margin="10,-76,0,9"
FontSize="187"
HorizontalAlignment="Left"

and if you decrease the font size without correction of top-margin, your title can be hidden or clipped by upper bound of the screen.

If you want to add image to the title, use the next sample as the base:

<controls:Panorama.TitleTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal">
            <Image x:Name="logoImage" Margin="0,80,0,0" Source="/ApplicationIcon.png" />
            <TextBlock Text="{Binding}" FontSize="100" Margin="0,50,0,0" />
        </StackPanel>
    </DataTemplate>
</controls:Panorama.TitleTemplate>
Panorama Image TitleTemplate

Image in title

Related posts:

Silverlight for Windows Phone 7: How to bind UserControl to itself (сontinuation)

June 20th, 2011 Admin 1 comment

     In one of my previous posts (How to bind UserControl to itself) I showed an implementation of BoundToSelfControl. It’s time to supplement this implementation with a new ability.

Obviously, if data, that should be rendered, is changed, we need to refresh our page in order that the actual values would be displayed. In other words, if at least one property of the object preserved in _source is changed, we have to be notified somehow about this fact and to refresh the displayed values. A standard approach is an usage of INotifyPropertyChanged, it’s precisely what is used by a standard binding system. Let’s do the same.

First of all, we need to subscribe to PropertyChanged event of our data source object, of course, if the one supports INotifyPropertyChanged. BoundToSelfControl‘s OnLoad method will look like

protected virtual void OnLoad()
{
    if (_source == null)
    {
        _source = DataContext;
        DataContext = this;

        INotifyPropertyChanged iNotifyPropertyChanged = _source as INotifyPropertyChanged;
        if (iNotifyPropertyChanged != null) // check if _source supports INotifyPropertyChanged;
            iNotifyPropertyChanged.PropertyChanged += new PropertyChangedEventHandler(iNotifyPropertyChanged_PropertyChanged); // subscribing to source property changes
    }
}

protected virtual void iNotifyPropertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
}

Secondly, BoundToSelfControl has to implement INotifyPropertyChanged as well in order to let the standard binding system know that it has to retake values of BoundToSelfControl‘s properties.

public class BoundToSelfControl : UserControl, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    // ... the rest of code

    // Raises the PropertyChanged event, passing the source property that is being updated
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Thirdly, in iNotifyPropertyChanged_PropertyChanged of a derived control we need to analyse what property of data source object is changed and then to fire PropertyChanged event with the name of appropriate property, for example, if ‘Price’ property of Product-object is changed, we fire PropertyChanged event with the ‘ProductPrice’ (Product class represents data to render).

public partial class ProductDispalyControl : BoundToSelfControl
{
    // ... the rest of code

    protected override void iNotifyPropertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if ("price".Equals(e.PropertyName, StringComparison.OrdinalIgnoreCase))
            NotifyPropertyChanged("ProductPrice");
        else
            if ("name".Equals(e.PropertyName, StringComparison.OrdinalIgnoreCase))
                NotifyPropertyChanged("ProductName");
    }
}

And the improved final version of BoundToSelfControl and ProductDispalyControl:

public class BoundToSelfControl : UserControl, INotifyPropertyChanged
{
    protected object _source = null;

    public event PropertyChangedEventHandler PropertyChanged;

    public BoundToSelfControl() : base()
    {
        Loaded += new RoutedEventHandler(BoundToSelfControl_Loaded);
    }

    protected virtual void OnLoad()
    {
        // NOTE: When we navigate from the current PhoneApplicationPage,
        // the state of the page is persisted (including the states of controls the page contains).
        // It's so called Tombstoning. If we get back to the persisted page,
        // BoundToSelfControl's Loaded-handler is called again (as opposed to the control constructor).
        // When it happens, DataContext already refers to the control itself, and there is no need to do anything else.
        // Of course, it's topical for windows phone 7 only
        if (_source == null)
        {
            _source = DataContext; // save data passed through DataContext in the field _source
            DataContext = this;    // bind to itself

            INotifyPropertyChanged iNotifyPropertyChanged = _source as INotifyPropertyChanged;
            if (iNotifyPropertyChanged != null) // check if _source supports INotifyPropertyChanged;
                iNotifyPropertyChanged.PropertyChanged += new PropertyChangedEventHandler(iNotifyPropertyChanged_PropertyChanged); // subscribing to source property changes
        }
    }

    protected virtual void OnDataSourcePropertyChanged(string propertyName)
    {
    }

    // Raises the PropertyChanged event, passing the source property that is being updated
    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    void iNotifyPropertyChanged_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        OnDataSourcePropertyChanged(e.PropertyName);
    }    

    void BoundToSelfControl_Loaded(object sender, RoutedEventArgs e)
    {
        OnLoad();
    }
}

public class Product
{
    public string Name  { get; set; }
    public double Price { get; set; }
}

public partial class ProductDispalyControl : BoundToSelfControl
{
    protected Product _product = null;

    public Product CurrentProduct
    {
        get
        {
            if (_product == null)
                _product = (Product)_source;
            return _product;
        }
    }

    public string ProductName
    {
        get { return string.Format("<{0}>", CurrentProduct.Name); }
    }

    public string ProductPrice
    {
        get { return string.Format("${0}", CurrentProduct.Price); }
    }

    public ProductDispalyControl()
    {
        InitializeComponent();
    }

    protected override void OnDataSourcePropertyChanged(string propertyName)
    {
        if ("price".Equals(propertyName, StringComparison.OrdinalIgnoreCase))
            NotifyPropertyChanged("ProductPrice");
        else
            if ("name".Equals(propertyName, StringComparison.OrdinalIgnoreCase))
                NotifyPropertyChanged("ProductName");
    }
}
Related posts: