Archive

Posts Tagged ‘C#’

C#: Get indented xml-based string

January 18th, 2012 No comments

    Manipulating XmlNodes we can get the result xml-based string using the InnerXml property of the XmlDocument-object the XmlNodes belong to. For example,

using System;
using System.Xml;
using System.IO;
...
// create XmlDocument object
XmlDocument xmlDOc = new XmlDocument();
xmlDOc.LoadXml(@"<rootNode><firstChildNode name=""first"" /></rootNode>");            

// manipulate with its nodes
XmlNode secondChildNode = xmlDOc.CreateElement("secondChildNode");
XmlAttribute nameAttr = xmlDOc.CreateAttribute("name");
nameAttr.Value = "secondChildNode";
secondChildNode.Attributes.Append(nameAttr);
XmlNode rootNode = xmlDOc.SelectSingleNode("/rootNode");
rootNode.AppendChild(secondChildNode);

// get the result xml-based string
string result = xmlDOc.InnerXml;

The following string is obtained:

<rootNode><firstChildNode name="first" /><secondChildNode name="secondChildNode" /></rootNode>

However, very often the result xml-based string is required to be formatted with indentations as it looks in many xml editors. The following method can be used for this:

public static string XmlDocToString(XmlDocument xmlDoc)
{
    StringWriter sw = new StringWriter();
    XmlTextWriter xw = new XmlTextWriter(sw);
    xw.Formatting = Formatting.Indented;
    xmlDoc.WriteTo(xw);
    return sw.ToString();
}

I usually use this method before displaying or saving the string in file. The indented result looks like:

<rootNode>
  <firstChildNode name="first" />
  <secondChildNode name="secondChildNode" />
</rootNode>

How to use:

string formattedStr = XmlDocToString(xmlDOc);
Categories: C#, XML Tags: ,

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

November 22nd, 2011 No 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:

WinForms: How to hide checkbox of the certain TreeNode in TreeView control

May 18th, 2011 4 comments

     Recently I needed to hide the checkboxes of some nodes in a TreeView-control, i.e. some nodes should be checkable, but the rest shouldn’t.

The standard TreeView doesn’t allow doing that directly, but Windows API will help us out. The main idea is to catch the moment when a node has been added to the TreeView, then to examine whether the node’s checkbox must be hidden and, if yes, to send a certain TVM_SETITEM message to the TreeView to hide the checkbox.

Unfortunately, the TreeView doesn’t provide us with an event to be fired right after a node has been added. So, we don’t have any choice, but to deal with WinAPI messages directly inside WndProc.

Having used .Net Reflector I’ve found out that while a node is being added to the Nodes-collection of either the TreeView or another node the following code is running (this piece of code is borrowed from the internal Realize method of the TreeNode class):

this.handle = UnsafeNativeMethods.SendMessage(
      new HandleRef(this.TreeView, this.TreeView.Handle), 
      NativeMethods.TVM_INSERTITEM, 0, ref lParam); // the first statement
treeView.nodeTable[this.handle] = this; // the second statement
this.UpdateNode(4); // the third statement

As we can see, after the first statement has been executed the TreeView receives a TVM_INSERTITEM message. In the WndProc of the TreeView, we could catch this message and fetch out the newly added node’s handle from it. The next step would be a getting a TreeNode-object corresponding to the handle as we need the latter to examine whether its checkbox must be hidden. However, at that stage the handle and the TreeNode wrapping it couldn’t yet be matched. The correct matching is available only after the pair <node’s handle, TreeNode-object> has been added to the TreeView‘s hashtable named nodeTable, in other words, after the second statement has completed. Evidently, the TVM_INSERTITEM message would be already processed by that moment. That means the TVM_INSERTITEM can’t be used, and we have to catch and handle another WinAPI message.

Luckily, right after the node has been added and the mapping between the handle and the TreeNode-object has been set up, the UpdateNode method (the third statement) emits a TVM_SETITEM message to the TreeView. So, I decided to handle this type of messages to hide unwanted checkboxes.

Below are two classes, HiddenCheckBoxTreeNode and MixedCheckBoxesTreeView, derived from the built-in TreeNode and TreeView classes respectively. The HiddenCheckBoxTreeNode class indicates a node with checkbox to be hidden. The MixedCheckBoxesTreeView class, in turn, hides unwanted checkboxes.

/// <summary>
/// Represents a node with hidden checkbox
/// </summary>
public class HiddenCheckBoxTreeNode : TreeNode
{
    public HiddenCheckBoxTreeNode() { }
    public HiddenCheckBoxTreeNode(string text) : base(text) { }
    public HiddenCheckBoxTreeNode(string text, TreeNode[] children) : base(text, children) { }
    public HiddenCheckBoxTreeNode(string text, int imageIndex, int selectedImageIndex) : base(text, imageIndex, selectedImageIndex) { }
    public HiddenCheckBoxTreeNode(string text, int imageIndex, int selectedImageIndex, TreeNode[] children) : base(text, imageIndex, selectedImageIndex, children) { }
    protected HiddenCheckBoxTreeNode(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) { }
}

public class MixedCheckBoxesTreeView : TreeView
{
    /// <summary>
    /// Specifies the attributes of a node
    /// </summary>
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct TV_ITEM
    {
        public int    Mask;
        public IntPtr ItemHandle;
        public int    State;
        public int    StateMask;
        public IntPtr TextPtr;
        public int    TextMax;
        public int    Image;
        public int    SelectedImage;
        public int    Children;
        public IntPtr LParam;
    }
 
    public const int TVIF_STATE          = 0x8;
    public const int TVIS_STATEIMAGEMASK = 0xF000;
 
    public const int TVM_SETITEMA = 0x110d;
    public const int TVM_SETITEM  = 0x110d;
    public const int TVM_SETITEMW = 0x113f;

    public const int TVM_GETITEM  = 0x110C;
 
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, ref TV_ITEM lParam);
 
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
 
        // trap TVM_SETITEM message
        if (m.Msg == TVM_SETITEM || m.Msg == TVM_SETITEMA || m.Msg == TVM_SETITEMW)
            // check if CheckBoxes are turned on
            if (CheckBoxes)
            {
                // get information about the node
                TV_ITEM tv_item = (TV_ITEM)m.GetLParam(typeof(TV_ITEM));
                HideCheckBox(tv_item);
            }
    }   
 
    protected void HideCheckBox(TV_ITEM tv_item)
    {
        if (tv_item.ItemHandle != IntPtr.Zero)
        {
            // get TreeNode-object, that corresponds to TV_ITEM-object
            TreeNode currentTN = TreeNode.FromHandle(this, tv_item.ItemHandle);
 
            HiddenCheckBoxTreeNode hiddenCheckBoxTreeNode = currentTN as HiddenCheckBoxTreeNode;
            // check if it's HiddenCheckBoxTreeNode and
            // if its checkbox already has been hidden

            if(hiddenCheckBoxTreeNode != null)
            {
                HandleRef treeHandleRef = new HandleRef(this, Handle);

                // check if checkbox already has been hidden
                TV_ITEM currentTvItem    = new TV_ITEM();
                currentTvItem.ItemHandle = tv_item.ItemHandle;
                currentTvItem.StateMask  = TVIS_STATEIMAGEMASK;
                currentTvItem.State      = 0;

                IntPtr res = SendMessage(treeHandleRef, TVM_GETITEM, 0, ref currentTvItem);
                bool needToHide = res.ToInt32() > 0 && currentTvItem.State != 0;

                if (needToHide)
                {
                    // specify attributes to update
                    TV_ITEM updatedTvItem    = new TV_ITEM();
                    updatedTvItem.ItemHandle = tv_item.ItemHandle;
                    updatedTvItem.Mask       = TVIF_STATE;
                    updatedTvItem.StateMask  = TVIS_STATEIMAGEMASK;
                    updatedTvItem.State      = 0;
 
                    // send TVM_SETITEM message
                    SendMessage(treeHandleRef, TVM_SETITEM, 0, ref updatedTvItem);
                }
            }
        }
    }
 
    protected override void OnBeforeCheck(TreeViewCancelEventArgs e)
    {
        base.OnBeforeCheck(e);
 
        // prevent checking/unchecking of HiddenCheckBoxTreeNode,
        // otherwise, we will have to repeat checkbox hiding
        if (e.Node is HiddenCheckBoxTreeNode)
            e.Cancel = true;
    }
}

Note the OnBeforeCheck method is intended to prohibit a TreeNode‘s Checked property changing, otherwise we would have to hide an appropriate checkbox again.

Below is a sample of using. Put a MixedCheckBoxesTreeView control upon a form and set a Load handler to the method listed below.

private void Form1_Load(object sender, EventArgs e)
{
    mixedCheckBoxesTreeView1.CheckBoxes = true;
    mixedCheckBoxesTreeView1.Nodes.Clear();

    HiddenCheckBoxTreeNode tn = new HiddenCheckBoxTreeNode("Root Node 1");
    mixedCheckBoxesTreeView1.Nodes.Add(tn);

    TreeNode tn2 = new TreeNode("Child Node Z");
    tn.Nodes.Add(tn2);

    HiddenCheckBoxTreeNode tn3 = new HiddenCheckBoxTreeNode("Child Node A");
    tn3.Checked = true; // just to test that nothing happens here
    tn.Nodes.Add(tn3);

    HiddenCheckBoxTreeNode tn4 = new HiddenCheckBoxTreeNode("Child Node X");
    tn.Nodes.Add(tn4);

    TreeNode tn5 = new TreeNode("Child Node D");
    tn.Nodes.Add(tn5);

    TreeNode tn6 = new TreeNode("Root Node 2");
    mixedCheckBoxesTreeView1.Nodes.Add(tn6);

    TreeNode tn7 = new TreeNode("Root Node 3");
    mixedCheckBoxesTreeView1.Nodes.Add(tn7);

    HiddenCheckBoxTreeNode tn8 = new HiddenCheckBoxTreeNode("Child Node A");
    tn7.Nodes.Add(tn8);

    mixedCheckBoxesTreeView1.ExpandAll();
}

To play with the approach implementation, download a Visual Studio 2010 solution from here.

Related posts: