In WPF there’s an interesting control called “InkCanvas” that can be used to capture signatures and the like in Tablet PC applications.
Recently I created a prototype for a windows forms application. I did consider using WPF, but the overhead seemed unnecessary considering the simplicity of the requirement.
I am aware there’s a specific SDK for Tablet PC that provides winforms controls for the requirement, but I thought it might be fun to create my own. As it turns out, it was pretty easy.
The requirement was to have a signature panel which could be used to collect a bitmap that would be attached to an entity to act as an authorisation.
Signature Panel
In the prototype I decided to create the signature panel as a standalone usercontrol called it, strangely enough “SignaturePanel”.
It uses Mousedown and MouseUp events to determine stylus pressure and mousemove for drawing. Like the WPF control it keeps a collection of strokes internally.
Unlike the wpf control, I just decided to expose a “SignatureImage” property to allow a developer to retrieve a bitmap. This is rendered from the strokes in realtime.
I assume it works for the Tablet PC, but I don’t know for sure.
Write your signature here
An additional feature of this control is a label which tells the user the last time the signature was last updated. I thought the user may find this helpful.
If the user hasn’t written anything then it just reads “Write your signature here”.
The user control consists of a picturebox called “inkPanel” and a button for resetting the content:
Here’s the code:
Public Class SignaturePanel
Private moCurrentWriting As New List(Of Point) Private Sub inkPanel_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles inkPanel.MouseMove Private Sub inkPanel_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles inkPanel.MouseUp moCurrentWriting = New List(Of Point) Private Sub inkPanel_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles inkPanel.Paint
mRenderSignature(e.Graphics)
Dim lsText As String = "" e.Graphics.DrawString(lsText, Me.Font, Brushes.Black, (inkPanel.Width / 2) - (e.Graphics.MeasureString(lsText, Me.Font).Width / 2), (inkPanel.Height / 2) - (e.Graphics.MeasureString(lsText, Me.Font).Height / 2)) <System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _ Return loBitmap End Class
Private moRememberInk As New List(Of List(Of Point))
Private mbPenDown As Boolean = False
Private Sub inkPanel_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles inkPanel.MouseDown
mbPenDown = True
End Sub
If mbPenDown Then
moCurrentWriting.Add(e.Location)
mdLastSignatureUpdate = Now
Me.Refresh()
End If
End Sub
If moCurrentWriting.Count > 2 Then
moRememberInk.Add(moCurrentWriting)
End If
mbPenDown = False
End Sub
If Not Me.DesignMode Then
If mdLastSignatureUpdate.HasValue Then
lsText = "Signature last updated " & Me.LastSignatureUpdate.ToLongTimeString
End If
e.Graphics.DrawString(lsText, Me.Font, Brushes.Black, 5, inkPanel.Height - 20)
Else
lsText = "... Write your signature here ..."
End If
End Sub
Private Sub mRenderSignature(ByVal g As Graphics)
Using loPen As New Pen(Color.Black)
loPen.Width = 2
For Each loLines As List(Of Point) In moRememberInk
g.DrawLines(loPen, loLines.ToArray)
Next
If moCurrentWriting.Count > 1 Then
g.DrawLines(loPen, moCurrentWriting.ToArray)
End If
End Using
End Sub
Private Sub cmdClearInk_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdClearInk.Click
moRememberInk.Clear()
inkPanel.Refresh()
End Sub
Private mdLastSignatureUpdate As Nullable(Of Date) = Nothing
<System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)> _
Public Property LastSignatureUpdate() As Date
Get
Return mdLastSignatureUpdate
End Get
Set(ByVal value As Date)
mdLastSignatureUpdate = value
End Set
End Property
Public ReadOnly Property SignatureImage() As Image
Get
Dim loBitmap As New Bitmap(Me.Width, Me.Height)
Using loGfx As Graphics = Graphics.FromImage(loBitmap)
mRenderSignature(loGfx)
End Using
End Get
End Property
If anyone’s interested in a standalone sample project, post the request to this blog and I’ll see what I can do.
Possible Uses
It may be interesting to use this code as:
- Signature recognition
- “Mud map” style sketching for business applications
- A basis for a drawing program
Of course, if you’re using WPF, use InkPanel. But if you don’t want the overhead, maybe this will be the foundation of a lightweight solution.

