NAVmoble - the pocket-sized ERP
Optimized for Microsoft Dynamics NAV and Windows Mobile powered devices

Saturday, December 09, 2006

"How To" Series: Building a Signature Control in Compact Framework

It is not a rare requirement for a mobile application to provide functionality for capturing a person signature.
So, let's see if we can provide this feature into a mobile application with .NET Compact Framework.
The image bellow outlines the problem that we want to solve:



We have a mobile salesman, who collects customer orders. Our salesman should collect the customer's signatures along with the order's details. Our salesman is carrying a Pocket PC device. We should create
a software solution to allow customer's signature capturing and transmition of the signature over the wire to the office. There we have a Sql Server database to store the signatures into and signatures consuming app. , which may process the stored signatures.


We should solve the following tasks:



  1. Capturing a signature from a person from the mobile device
  2. Saving the captured signature locally on the mobile device
  3. Transmitting the saved signature over the wire and storing it on the server side
  4. Consuming the transmitted and saved signature on the server side

Let's try to solve these tasks:


Solving Task 1: Capturing a signature from a person on the mobile device


If a person should place its signature on a Pocket PC, he will probably use the stylus to write his signature on the Pocket PC screen. All we have to do is to capture the on-screen tapings and convert them into a bitmap. We will create a User Control to encapsulate this functionality. The main functionality is divided between the following UserControl event handlers:



  • OnMouseDown - here we will "remember" the coordinates of the last on-screen tapping
  • OnMouseMove - here we will draw a line from the remembered coordinates to the new(after the mouse move) on-screen mouse coordinates.


Following code example(simplified version)
...
private Bitmap SignatureImage;
private Graphics GraphicsHandle;
privte Point MouseCoords;
....
SignatureImage = new Bitmap(this.Width, this.Height);
GraphicsHandle = Graphics.FromImage(SignatureImage);
...
//remembering the coords of the last on-screen tapping into  MouseCoords member
protected override void OnMouseDown(MouseEventArgs e)
{
  base.OnMouseDown(e);
  MouseCoords.X = e.X;
  MouseCoords.Y = e.Y;
}
//draw a line from the remembered coords to the new on-screen tapping coords
protected override void OnMouseMove(MouseEventArgs e)
{
  base.OnMouseMove(e); 
  GraphicsHandle.DrawLine(SignaturePen, MouseCoords.X, MouseCoords.Y, e.X, e.Y); 
  MouseCoords.X = e.X;
  MouseCoords.Y = e.Y;

//saves the captured bitmap image into a stream
public void Save(Stream stream)
{
   SignatureImage.Save(stream, ImageFormat.Bmp);
}  


Solving Task 2: Saving the captured signature locally on the mobile device


This task is simpler. Let's pretend, we should save the captured image into a local SqlServer Mobile database.
We should have a table containing a field of type image to save the signature into it.



CRATE TABLE CUSTOMERSIGN
{


   customerNo:int not null identity
   sign:image
}


Following the code to save the captured signature:


//our signature control placed into a form
private
SignatureControl MySignatureControl;
...
string connectionString =  ...;
...
using (SqlCeConnection connection = new SqlCeConnection(connectionString))
{
  connection.Open();
  SqlCeCommand command = new SqlCeCommand("INSERT INTO CUSTOMERSIGN(sign)VALUES(?)", connection); 
 


  //getting the captured signature as stream
  MemoryStream signStream = new MemoryStream();
  MySignatureControl.Save(signStream);


  param = new SqlCeParameter("sign", SqlDbType.Binary);
  param.Value = signStream.ToArray();
  command.Parameters.Add(param);


  command.ExecuteNonQuery();
  connection.Close();
}
Now we have the signature saved locally...
We may save the signature into another storage type like a file for example.


Solving Task 3: Transmitting the saved signature over the wire


Usually the most valuable mobile applications provide functionality to send and receive data to/from some in-house systems running in the company's office.
Let's see if we can send the captured image back to the office over the wire. Although there are various communication options that may be used to transmit the signature over the wire, we will see only the Xml Web Services way in this article. Other possible options are TCP/IP transmition with sockets, Merge Replication,RDA  and why not E-mail .
First, we should create our Xml Web Service. This Xml Web Service will run on the company's office web server. The web server its self should be "http reachable" by  our PocketPC. So, when our Pocket PC device gets a network connection, it may invoke our Xml Web Service and send all the captured signs back to the office.
Let's have a similar table (CUSTOMERSIGN) created into a Sql Server, which also runs in our office. Our Xml Web Service will receive the captured signatures from the mobile app. and will save them into the CUSTOMERSIGN table in the Sql Server. Later another app. may fetch the stored signs to process them in some way.


The  Xml Web Service will have one web method like this:




[WebMethod]
public void TransmitSignature(int customerId, byte[]
signature)
{
  using(SqlConnection connection = new SqlConnection(connectionString))
  {
     SqlCommand insertCmd = new SqlCommand("INSERT INTO CUSTOMERSIGN(customerId,sign)VALUES(@customerId,@signature)", connection); 
     insertCmd.Parameters.AddWithValue("@customerId", customerId); 
     insertCmd.Parameters.AddWithValue("@signature",signature);
     insertCmd.ExecuteNonQuery();
  }


}


Then on the mobile side, we may create a web reference to our Web service and consume it, when a network connection is available


OfficeService.SignService signService = new OfficeService.SignService();
using(SqlCeConnection cnn = new SqlCeConnection(connectionString))
{      


        SqlCeCommand cmd = new SqlCeCommand("SELECT customerId,signature FROM CUSTOMERSIGN",cnn);
        SqlCeDataReader reader  =  cmd.ExecuteReader();
        while(reader.Read())
        {
            int customerId= (int)reader[0];


            //read the signature from the mobile database
            int imgSize = reader.GetBytes(1,0,null,0,0); 
            byte[] signImageData = new byte[imgSize];
            reader.GetBytes(1,0,signImageData,0,0); 


            //transmit signature over the wire
            signService.TransmitSignature(customerId,signImageData);
         }          


         //delete transmited signatures from the mobile database
         
SqCeCommand deleteCmd = new SqCeCommand("DELETE FROM CUSTOMERSIGN",cnn);
         deleteCmd.ExecuteNonQuery();
 } 


Note, that this example is not quite efficient from a performance point of view. It will be more performant to have a Web Method, which accepts
a collection of signatures at a time. It may be performed easily by using DataSet to fetch and  transfer the captured signatures:

[WebMethod]
public void
TransmitSignature(DataSet signatures
)

Solving Task 4: Visualizing the transmited signature on the server side


Once we have the captured signatures saved on the server side, we may need to consume them. For example we may want to show them as images on the screen.
In order to do this we should fetch them from the database:



//picturebox control to show the signature
private PictureBox pictureBox1;
...
int interestingCusotmerId;
 ...
SqlCommand cmd = new SqlCommand("SELECT signature FROM CUSTOMERSIGN WHERE customerId=@customerId", connection);
cmd.Parameters.AddWithValue("@customerId",interestingCusotmerId);
SqlDataReader reader  =  cmd.ExecuteReader();
if(reader.Read())
{
    //read the signature from the database
    int imgSize = reader.GetBytes(0,0,null,0,0); 
    byte[] signImageData = new byte[imgSize];
    reader.GetBytes(0,0,signImageData,0,0);
    //show the signature as Bitmap image
    using(MemoryStream ms = new MemoryStream(signImageData))
    {
      pictureBox1.Image = new Bitmap(ms);
    }
}          


The presented example is not a complete solution. It just outlines some of the common problems, which should be addressed if one needs to build a signature capturing solution. 
A real world solution may be far more complicated and should address a lot of problems not mentioned here. For example there are other signature capturing techniques ,which may store the signature in more compressed format. One may need to encrypt/decrypt the captured signature to protect it or validate the signature(biometric). Please see the links bellow for more examples.



Links:


Monday, December 04, 2006

WPF/E CTP is out

Microsoft released the first CTP for WPF/E.

“WPF/E” is the Microsoft solution for delivering rich, cross-platform, interactive experiences including animation, graphics, audio, and video for the Web and beyond. Utilizing a subset of XAML (eXtensible Application Markup Language)-based Windows Presentation Foundation technology, “WPF/E” will enable the creation of content and applications that run within multiple browsers and operating systems (Windows and Macintosh) using Web standards for programmability. Consistent with Web architecture, the XAML markup is programmable using JavaScript and works well with ASP.NET AJAX. Broadly available for customers in the first half of 2007, “WPF/E” experiences will require a lightweight browser plug-in made freely available by Microsoft.



The CTP contains the WPF/E plugin itself and SDK



There is a Macintosh version as well

Links:

WPF/E Downloads

WPF/E Dev Center

Sunday, December 03, 2006

Microsoft Days in Sofia University

I had a short presentation discussing the .NET Compact Framework goodies, during the Microsoft Days in the Sofia University
The Slides and the source code are available(in Bulgarian):
If you have any questions or troubles compiling the source code, please contact me at r underscore trifonov at hotmail dot com

Friday, December 01, 2006

"How To" Series: Detect network connection in Compact Framework

There is several ways to accomplish this and I will outline some of them in this post.


The following snippet may be used to detect if the device is connected to a network.
It checks if the device has an IP address assigned. This approach will not work properly if the device has a static IP. It is not guaranteed that a specific network destination is reachable.


bool IsConnected
{
    get
    { 
        try
        {  
            string hostName = Dns.GetHostName(); 
            IPHostEntry curHost = Dns.GetHostByName(hostName); 
            return curHost.AddressList[0].ToString() != IPAddress.Loopback.ToString(); 
        } 
        catch
        {
            return false; 
        }
    }
}


Another possible approach is to check if there is a "path" to a specific destination.


public bool IsNetworkPathAvailable(string destinationAddress)
{
     bool connected = false
     HttpWebRequest request;
     HttpWebResponse response;
     try
     {
          request = (HttpWebRequest)WebRequest.Create(destinationAddress);
          response = (HttpWebResponse)request.GetResponse();
          request.Abort(); 
          if (response.StatusCode == HttpStatusCode.OK)
         {
              connected = true;
         }
    }
    catch (WebException ex)
    {
        connected = false;
    }
    catch (Exception ex)
    {
       connected = false;
    }
    finally
    {
       if(response != null)
          response.Close();    
    }
    return connected;
 }
//here we will use the network detection
if(IsNetworkPathAvailable(http://www.ritsoftware.com"))
            SendSomeDataOverTheWire();  


Another way to accomplish this is to use the InternetGetConnectedState function from wininet.dll
[DllImport("wininet.dll")]
private static extern bool InternetGetConnectedState(ref uint flags, uint dwReserved);

public bool IsConnected
{
   get
   {
        uint flags;
        return InternetGetConnectedState(ref flags,0);
   }
}  


 


Links
ConnectionManager class from www.opennetcf.org
Compact Framework Newsgroups


 


 


 

Wednesday, November 01, 2006

WCF on the mobile side

Roman Batoukov has a post explaining in details the plans about providing Windows Communication Foundation support in the .NET Compact Framework.
The programming model provided will be limited to channel layer messaging only. It will be extensible, so the developers eventually will be able to implement their own transports. Few out-of-the box transport channels will be delivered like Http and E-mail.

Roman discusses some common problems regarding the devices communication , their solutions(when the WCF is out) and the feature of the E-mail as a messaging transport.

Read the full article