Solved

Visual Studio Community 2015: How to save a signature using Inkpicture object, either to a folder or to access

Posted on 2016-08-09
8
38 Views
Last Modified: 2016-09-10
I'm creating a series of apps for my work to inventory orders, loaners, etc. and I've gotten most everything created. The problem I'm having is with signatures. The user will need to sign for whatever they're getting. To achieve this, I'm using an Inkpicture object. It works great, except when I use the save method, I get InvalidCast Exception.

Here is the code I'm using to save:

Private Sub SaveButton_Click(sender As System.Object, e As System.EventArgs) Handles SaveButton.Click


        If myConnection.State = ConnectionState.Closed Then

            myConnection.Open()

        End If

        Dim str As String

        str = "Update [Items] SET [Picked] = '" & escapeQutoes(Controls("Picked").Text) & "', [Datepicked] = '" & escapeQutoes(Controls("Datepicked").Text) & "', [Tech] = '" & escapeQutoes(Controls("Tech").Text) & "' WHERE [RITMWO] = '" & escapeQutoes(Controls("RITMWO").Text) & "'"

        Dim cmd As OleDbCommand = New OleDbCommand(str, myConnection)

        Dim targetFilename As String = "C:\Users\Dudeman\Desktop\Sigs\'" & RITMWO.Text & "'.jpg"

        Signature.Ink.Save(targetFilename)

        Try

            cmd.ExecuteNonQuery()

            cmd.Dispose()

            myConnection.Close()

            MsgBox("Records Updated Successfully")

        Catch ex As Exception

            MsgBox(ex.Message)

        End Try



    End Sub

 Public Function escapeQutoes(input As String) As String

        If input.Contains("'") Then

            input = input.Replace("'", "''")

        End If

        Return input

    End Function

Open in new window


I haven't been able to find anything useful in my two weeks of searching for the answer. Can anyone help me? I've tried changing the file type to .gif, bmp, and .isf with no change.

Ultimately, I'm looking to save this into the Access database it's pulling and saving to anyway (for the other information being saved), but I'm trying to get the signature saved any way I can.

InvalidCastException
0
Comment
Question by:Mike B.
  • 3
  • 3
8 Comments
 
LVL 32

Expert Comment

by:it_saige
ID: 41749027
Not that this is the root cause of your problem, but this may be incorrect:
Dim targetFilename As String = "C:\Users\Dudeman\Desktop\Sigs\'" & RITMWO.Text & "'.jpg"
' Produces a string like - C:\Users\Dudeman\Desktop\Sigs\'TEST'.jpg

Open in new window

You probably want it to be:
Dim targetFilename As String = "C:\Users\Dudeman\Desktop\Sigs\" & RITMWO.Text & ".jpg"
' Produces a string like - C:\Users\Dudeman\Desktop\Sigs\TEST.jpg

Open in new window


As to the root cause of your problem, the Save method that you have referenced is expecting a PersistenceFormat parameter, which is an int based enumeration.

The exception is that you cannot convert a string to an int.

So is the ink image actually stored and you are trying to load it?  Are you wishing to store it as a blob in the database (personally I would, that way any device that accesses the database can download and view/print the image)?

-saige-
1
 

Author Comment

by:Mike B.
ID: 41749113
It won't save at all. I would like to store it as a blob though, since I will eventually create a receipt to send the users (later project).
0
 
LVL 32

Expert Comment

by:it_saige
ID: 41749119
So I am assuming that Signature is your Ink object.  Is this a correct assumption?

-saige-
1
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:Mike B.
ID: 41749121
That is correct.
0
 
LVL 32

Accepted Solution

by:
it_saige earned 500 total points
ID: 41750954
My apologize for the amount of time it has taken to put this together, but I wanted as simple and complete of an example as possible.

So here goes.

SQL Table Configuration:
CREATE TABLE [dbo].[People] (
    [Id]          INT           IDENTITY (1, 1) NOT NULL,
    [Name]        VARCHAR (MAX) NULL,
    [Birthdate]   DATETIME      NULL,
    [SignatureID] INT           DEFAULT ((-1)) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

CREATE TABLE [dbo].[Signatures] (
    [Id]   INT             IDENTITY (1, 1) NOT NULL,
    [Name] VARCHAR (MAX)   NULL,
    [Data] VARBINARY (MAX) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

Open in new window

Form1.vb -
Imports System.ComponentModel

Public Class Form1
	Private frmPerson As PersonForm
	Private people As New BindingList(Of Person)

	Private Sub OnLoad(sender As Object, e As EventArgs) Handles MyBase.Load
		LoadPeople()
		Binder.DataSource = people
		DataGridView1.DataSource = Binder
	End Sub

	Private Sub OnRowContextMenuStripNeeded(sender As Object, e As DataGridViewRowContextMenuStripNeededEventArgs) Handles DataGridView1.RowContextMenuStripNeeded
		If TypeOf sender Is DataGridView Then
			Dim dgv = DirectCast(sender, DataGridView)
			If Not dgv.SelectedRows.Contains(dgv.Rows(e.RowIndex)) Then dgv.Rows(e.RowIndex).Selected = True
			e.ContextMenuStrip = RowContext
		End If
	End Sub

	Private Sub OnClick(sender As Object, e As EventArgs) Handles AddPersonToolStripMenuItem.Click, EditPersonToolStripMenuItem.Click, DeletePersonToolStripMenuItem.Click
		If TypeOf sender Is ToolStripMenuItem Then
			If frmPerson IsNot Nothing Then frmPerson.Dispose()

			Dim menu = DirectCast(sender, ToolStripMenuItem)
			Dim current = If(DataGridView1.SelectedRows.Count = 1, DirectCast(DataGridView1.SelectedRows(0).DataBoundItem, Person), New Person())
			If menu.Equals(AddPersonToolStripMenuItem) Then
				frmPerson = New PersonForm(New Person())
				If frmPerson.ShowDialog() = DialogResult.OK Then people.Add(frmPerson.Person)
			ElseIf menu.Equals(DeletePersonToolStripMenuItem) Then
				DeletePerson(current)
			ElseIf menu.Equals(EditPersonToolStripMenuItem) Then
				frmPerson = New PersonForm(current)
				frmPerson.ShowDialog()
			End If
		End If
	End Sub

	Private Sub LoadPeople()
		If people IsNot Nothing Then people = New BindingList(Of Person)
		Try
			Connection.Open()
			Using _ds As New DataSet()
				_ds.Tables.AddRange(New DataTable() {New DataTable("People"), New DataTable("Signatures")})

				PersonAdapter.Fill(_ds.Tables("People"))
				SignatureAdapter.Fill(_ds.Tables("Signatures"))
				For Each row As DataRow In _ds.Tables(0).Rows()
					people.Add(New Person() With {.ID = CType(row("ID"), Integer), .Name = CType(row("NAME"), String), .Birthdate = CType(row("BIRTHDATE"), DateTime), .SignatureID = CType(row("SIGNATUREID"), Integer), .Signature = GetThumbnail(.SignatureID, _ds.Tables("Signatures"))})
				Next
			End Using
		Catch ex As Exception
		Finally
			Connection.Close()
		End Try
	End Sub

	Private Sub DeletePerson(current As Person)
		If current IsNot Nothing Then
			Try
				Connection.Open()
				If current.SignatureID <> -1 Then
					SignatureAdapter.DeleteCommand.Parameters("@ID").Value = current.SignatureID
					SignatureAdapter.DeleteCommand.ExecuteNonQuery()
				End If

				If current.ID <> -1 Then
					PersonAdapter.DeleteCommand.Parameters("@ID").Value = current.ID
					PersonAdapter.DeleteCommand.ExecuteNonQuery()
				End If

				For Each [person] In people.Reverse()
					If [person].ID.Equals(current.ID) Then
						people.Remove([person])
					End If
				Next
			Catch ex As Exception
				MessageBox.Show(ex.Message)
			Finally
				Connection.Close()
			End Try
		End If
	End Sub

	Private Sub OnCellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles DataGridView1.CellFormatting
		If TypeOf sender Is DataGridView Then
			Dim grid = DirectCast(sender, DataGridView)
			If grid.Rows.Count > 0 Then
				If grid.Columns(e.ColumnIndex).Name.Equals("birthdate", StringComparison.OrdinalIgnoreCase) Then
					e.Value = CType(e.Value, DateTime).ToShortDateString()
					e.FormattingApplied = True
				ElseIf grid.Columns(e.ColumnIndex).Name.Equals("signature", StringComparison.OrdinalIgnoreCase) Then

				End If
			End If
		End If
	End Sub

	Private Function GetThumbnail(ByVal id As Integer, ByVal table As DataTable) As Image
		Dim image As Image = Nothing
		If id <> -1 AndAlso table IsNot Nothing Then
			Try
				Dim data = (From row As DataRow In table.Rows Where CType(row("ID"), Integer).Equals(id) Select CType(row("DATA"), Byte())).FirstOrDefault()
				If data IsNot Nothing Then
					image = data.ToImage().GetThumbnailImage()
				End If
			Catch ex As Exception
				image = Nothing
			End Try
		End If
		Return image
	End Function
End Class

Open in new window

Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
		Me.components = New System.ComponentModel.Container()
		Me.DataGridView1 = New System.Windows.Forms.DataGridView()
		Me.GridContext = New System.Windows.Forms.ContextMenuStrip(Me.components)
		Me.AddPersonToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
		Me.RowContext = New System.Windows.Forms.ContextMenuStrip(Me.components)
		Me.EditPersonToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
		Me.DeletePersonToolStripMenuItem = New System.Windows.Forms.ToolStripMenuItem()
		Me.Binder = New System.Windows.Forms.BindingSource(Me.components)
		CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).BeginInit()
		Me.GridContext.SuspendLayout()
		Me.RowContext.SuspendLayout()
		CType(Me.Binder, System.ComponentModel.ISupportInitialize).BeginInit()
		Me.SuspendLayout()
		'
		'DataGridView1
		'
		Me.DataGridView1.AllowUserToAddRows = False
		Me.DataGridView1.AllowUserToDeleteRows = False
		Me.DataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
		Me.DataGridView1.ContextMenuStrip = Me.GridContext
		Me.DataGridView1.Dock = System.Windows.Forms.DockStyle.Fill
		Me.DataGridView1.Location = New System.Drawing.Point(0, 0)
		Me.DataGridView1.MultiSelect = False
		Me.DataGridView1.Name = "DataGridView1"
		Me.DataGridView1.ReadOnly = True
		Me.DataGridView1.RowHeadersVisible = False
		Me.DataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect
		Me.DataGridView1.Size = New System.Drawing.Size(501, 261)
		Me.DataGridView1.TabIndex = 0
		'
		'GridContext
		'
		Me.GridContext.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.AddPersonToolStripMenuItem})
		Me.GridContext.Name = "GridContext"
		Me.GridContext.Size = New System.Drawing.Size(136, 26)
		'
		'AddPersonToolStripMenuItem
		'
		Me.AddPersonToolStripMenuItem.Name = "AddPersonToolStripMenuItem"
		Me.AddPersonToolStripMenuItem.Size = New System.Drawing.Size(135, 22)
		Me.AddPersonToolStripMenuItem.Text = "Add Person"
		'
		'RowContext
		'
		Me.RowContext.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.EditPersonToolStripMenuItem, Me.DeletePersonToolStripMenuItem})
		Me.RowContext.Name = "RowContext"
		Me.RowContext.Size = New System.Drawing.Size(147, 48)
		'
		'EditPersonToolStripMenuItem
		'
		Me.EditPersonToolStripMenuItem.Name = "EditPersonToolStripMenuItem"
		Me.EditPersonToolStripMenuItem.Size = New System.Drawing.Size(146, 22)
		Me.EditPersonToolStripMenuItem.Text = "Edit Person"
		'
		'DeletePersonToolStripMenuItem
		'
		Me.DeletePersonToolStripMenuItem.Name = "DeletePersonToolStripMenuItem"
		Me.DeletePersonToolStripMenuItem.Size = New System.Drawing.Size(146, 22)
		Me.DeletePersonToolStripMenuItem.Text = "Delete Person"
		'
		'Form1
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(501, 261)
		Me.Controls.Add(Me.DataGridView1)
		Me.Name = "Form1"
		Me.Text = "Form1"
		CType(Me.DataGridView1, System.ComponentModel.ISupportInitialize).EndInit()
		Me.GridContext.ResumeLayout(False)
		Me.RowContext.ResumeLayout(False)
		CType(Me.Binder, System.ComponentModel.ISupportInitialize).EndInit()
		Me.ResumeLayout(False)

	End Sub
	Friend WithEvents DataGridView1 As System.Windows.Forms.DataGridView
	Friend WithEvents GridContext As System.Windows.Forms.ContextMenuStrip
	Friend WithEvents AddPersonToolStripMenuItem As System.Windows.Forms.ToolStripMenuItem
	Friend WithEvents RowContext As System.Windows.Forms.ContextMenuStrip
	Friend WithEvents EditPersonToolStripMenuItem As System.Windows.Forms.ToolStripMenuItem
	Friend WithEvents DeletePersonToolStripMenuItem As System.Windows.Forms.ToolStripMenuItem
	Friend WithEvents Binder As System.Windows.Forms.BindingSource

End Class

Open in new window

PersonForm.vb -
Imports Microsoft.Ink

' Credit to bigbro_1985 for the InkCollector and GroupBox idea
' http://www.codeproject.com/Articles/105570/InkCollector-Signiture-Made-Easy
Public Class PersonForm
	Friend WithEvents _collector As InkCollector
	Private ReadOnly _person As Person
	Private ReadOnly _signature As Signature

	Public ReadOnly Property [Person]() As Person
		Get
			Return _person
		End Get
	End Property

	Public ReadOnly Property [Signature]() As Signature
		Get
			Return _signature
		End Get
	End Property

	Public Sub New(p As Person)
		InitializeComponent()
		_person = If(p IsNot Nothing, p, New Person())
		_signature = New Signature()
	End Sub

	Private Sub OnLoad(sender As Object, e As EventArgs) Handles MyBase.Load
		_collector = New InkCollector(gbSignature.Handle) With {.AutoRedraw = True, .Enabled = True}
		If _person.ID <> -1 Then
			tbName.Text = _person.Name
			dtpBirthdate.Value = _person.Birthdate
			If _person.SignatureID <> -1 Then
				Try
					Connection.Open()
					Using _ds As New DataSet()
						Dim _temp As Signature = Nothing
						SignatureAdapter.Fill(_ds)
						Try
							_temp = (From row As DataRow In _ds.Tables(0).Rows
								    Where CType(row("ID"), Integer).Equals(_person.SignatureID)
								    Select New Signature() With {.ID = CType(row("ID"), Integer), .Name = CType(row("NAME"), String), .Data = CType(row("DATA"), Byte())}).FirstOrDefault()
						Catch ex As Exception
							_temp = Nothing
						End Try

						If _temp IsNot Nothing Then
							_signature.ID = _temp.ID
							_signature.Name = _temp.Name
							_signature.Data = _temp.Data
						End If
					End Using
				Catch ex As Exception
					MessageBox.Show(ex.Message)
				Finally
					Connection.Close()
				End Try
			End If
		End If
		_collector.SetInk(gbSignature, _signature.Data)
	End Sub

	Private Sub OnClick(sender As Object, e As EventArgs) Handles btnClear.Click, btnOK.Click, btnCancel.Click
		If TypeOf sender Is Button Then
			Dim btn = DirectCast(sender, Button)
			If btn.Equals(btnClear) Then
				_collector.Clear(gbSignature)
			ElseIf btn.Equals(btnOK) Then
				Try
					[Connection].Open()
					UpdateSignature()
					UpdatePerson()
					DialogResult = DialogResult.OK
					Close()
				Catch ex As Exception
					MessageBox.Show(ex.Message)
				Finally
					[Connection].Close()
				End Try
			ElseIf btn.Equals(btnCancel) Then
				DialogResult = DialogResult.Cancel
				Close()
			End If
		End If
	End Sub

	Private Sub UpdateSignature()
		If [Connection].State = ConnectionState.Open Then
			If _signature.ID = -1 Then _signature.Name = String.Format("{0}.gif", Guid.NewGuid())
			_signature.Data = _collector.ToByteArray()

			If _signature.ID = -1 Then
				SignatureAdapter.InsertCommand.Parameters("@NAME").Value = _signature.Name
				SignatureAdapter.InsertCommand.Parameters("@DATA").Value = _signature.Data
				_signature.ID = CType(SignatureAdapter.InsertCommand().ExecuteScalar(), Integer)
			Else
				SignatureAdapter.UpdateCommand.Parameters("@NAME").Value = _signature.Name
				SignatureAdapter.UpdateCommand.Parameters("@DATA").Value = _signature.Data
				SignatureAdapter.UpdateCommand.Parameters("@ID").Value = _signature.ID
				SignatureAdapter.UpdateCommand().ExecuteNonQuery()
			End If
		End If
	End Sub

	Private Sub UpdatePerson()
		If [Connection].State = ConnectionState.Open Then
			_person.Name = tbName.Text
			_person.Birthdate = dtpBirthdate.Value
			_person.SignatureID = _signature.ID
			_person.Signature = _signature.Data.ToImage().GetThumbnailImage()

			If _person.ID = -1 Then
				PersonAdapter.InsertCommand.Parameters("@NAME").Value = _person.Name
				PersonAdapter.InsertCommand.Parameters("@BIRTHDATE").Value = _person.Birthdate
				PersonAdapter.InsertCommand.Parameters("@SIGNATUREID").Value = _person.SignatureID
				_person.ID = CType(PersonAdapter.InsertCommand().ExecuteScalar(), Integer)
			Else
				PersonAdapter.UpdateCommand.Parameters("@NAME").Value = _person.Name
				PersonAdapter.UpdateCommand.Parameters("@BIRTHDATE").Value = _person.Birthdate
				PersonAdapter.UpdateCommand.Parameters("@SIGNATUREID").Value = _person.SignatureID
				PersonAdapter.UpdateCommand.Parameters("@ID").Value = _person.ID
				PersonAdapter.UpdateCommand().ExecuteNonQuery()
			End If
		End If
	End Sub
End Class

Open in new window

PersonForm.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class PersonForm
	Inherits System.Windows.Forms.Form

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		Me.lblName = New System.Windows.Forms.Label()
		Me.tbName = New System.Windows.Forms.TextBox()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.dtpBirthdate = New System.Windows.Forms.DateTimePicker()
		Me.gbSignature = New System.Windows.Forms.GroupBox()
		Me.btnClear = New System.Windows.Forms.Button()
		Me.btnOK = New System.Windows.Forms.Button()
		Me.btnCancel = New System.Windows.Forms.Button()
		Me.SuspendLayout()
		'
		'lblName
		'
		Me.lblName.AutoSize = True
		Me.lblName.Location = New System.Drawing.Point(9, 11)
		Me.lblName.Name = "lblName"
		Me.lblName.Size = New System.Drawing.Size(38, 13)
		Me.lblName.TabIndex = 0
		Me.lblName.Text = "Name:"
		'
		'tbName
		'
		Me.tbName.Location = New System.Drawing.Point(66, 8)
		Me.tbName.Name = "tbName"
		Me.tbName.Size = New System.Drawing.Size(206, 20)
		Me.tbName.TabIndex = 1
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(9, 41)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(52, 13)
		Me.Label1.TabIndex = 2
		Me.Label1.Text = "Birthdate:"
		'
		'dtpBirthdate
		'
		Me.dtpBirthdate.CustomFormat = "MM/dd/yyyy"
		Me.dtpBirthdate.Location = New System.Drawing.Point(66, 35)
		Me.dtpBirthdate.Name = "dtpBirthdate"
		Me.dtpBirthdate.Size = New System.Drawing.Size(206, 20)
		Me.dtpBirthdate.TabIndex = 3
		'
		'gbSignature
		'
		Me.gbSignature.Location = New System.Drawing.Point(12, 61)
		Me.gbSignature.Name = "gbSignature"
		Me.gbSignature.Size = New System.Drawing.Size(260, 100)
		Me.gbSignature.TabIndex = 4
		Me.gbSignature.TabStop = False
		Me.gbSignature.Text = "Sign Here"
		'
		'btnClear
		'
		Me.btnClear.Location = New System.Drawing.Point(197, 167)
		Me.btnClear.Name = "btnClear"
		Me.btnClear.Size = New System.Drawing.Size(75, 23)
		Me.btnClear.TabIndex = 7
		Me.btnClear.Text = "Clear"
		Me.btnClear.UseVisualStyleBackColor = True
		'
		'btnOK
		'
		Me.btnOK.Location = New System.Drawing.Point(116, 226)
		Me.btnOK.Name = "btnOK"
		Me.btnOK.Size = New System.Drawing.Size(75, 23)
		Me.btnOK.TabIndex = 5
		Me.btnOK.Text = "OK"
		Me.btnOK.UseVisualStyleBackColor = True
		'
		'btnCancel
		'
		Me.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel
		Me.btnCancel.Location = New System.Drawing.Point(197, 226)
		Me.btnCancel.Name = "btnCancel"
		Me.btnCancel.Size = New System.Drawing.Size(75, 23)
		Me.btnCancel.TabIndex = 6
		Me.btnCancel.Text = "Cancel"
		Me.btnCancel.UseVisualStyleBackColor = True
		'
		'PersonForm
		'
		Me.AcceptButton = Me.btnOK
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.CancelButton = Me.btnCancel
		Me.ClientSize = New System.Drawing.Size(284, 261)
		Me.Controls.Add(Me.btnClear)
		Me.Controls.Add(Me.btnCancel)
		Me.Controls.Add(Me.btnOK)
		Me.Controls.Add(Me.gbSignature)
		Me.Controls.Add(Me.dtpBirthdate)
		Me.Controls.Add(Me.Label1)
		Me.Controls.Add(Me.tbName)
		Me.Controls.Add(Me.lblName)
		Me.Name = "PersonForm"
		Me.Text = "Person"
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents lblName As System.Windows.Forms.Label
	Friend WithEvents tbName As System.Windows.Forms.TextBox
	Friend WithEvents Label1 As System.Windows.Forms.Label
	Friend WithEvents dtpBirthdate As System.Windows.Forms.DateTimePicker
	Friend WithEvents gbSignature As System.Windows.Forms.GroupBox
	Friend WithEvents btnClear As System.Windows.Forms.Button
	Friend WithEvents btnOK As System.Windows.Forms.Button
	Friend WithEvents btnCancel As System.Windows.Forms.Button
End Class

Open in new window

SupportingObjects.vb -
Imports Microsoft.Ink
Imports System.ComponentModel
Imports System.Data.SqlClient
Imports System.IO

' Credit to bigbro_1985 for the InkCollector and GroupBox idea
' http://www.codeproject.com/Articles/105570/InkCollector-Signiture-Made-Easy
Module Extensions
	<System.Runtime.CompilerServices.Extension()> _
	Public Sub Clear(collector As InkCollector, gb As GroupBox)
		If collector IsNot Nothing AndAlso gb IsNot Nothing Then
			collector.Enabled = False
			collector.Ink.DeleteStrokes()
			gb.Invalidate()
			collector.Enabled = True
		End If
	End Sub

	<System.Runtime.CompilerServices.Extension()> _
	Public Function GetThumbnailImage(source As Image) As Image
		Return If(source IsNot Nothing, source.GetThumbnailImage(30, 15, AddressOf GetThumbnailImageCallback, IntPtr.Zero), Nothing)
	End Function

	Private Function GetThumbnailImageCallback() As Boolean
		Return False
	End Function

	<System.Runtime.CompilerServices.Extension()> _
	Public Sub SetInk(collector As InkCollector, gb As GroupBox, data As Byte())
		If collector IsNot Nothing AndAlso gb IsNot Nothing AndAlso data IsNot Nothing Then
			Dim loaded = New Ink()
			collector.Enabled = False
			collector.Ink.DeleteStrokes()
			loaded.Load(data)
			collector.Ink = loaded
			collector.Enabled = True
			gb.Invalidate()
		End If
	End Sub

	<System.Runtime.CompilerServices.Extension()> _
	Public Function ToByteArray(collector As InkCollector) As Byte()
		If collector IsNot Nothing Then
			Try
				collector.Enabled = False
				Return collector.Ink.Save(PersistenceFormat.Gif, CompressionMode.Maximum)
			Finally
				collector.Enabled = True
			End Try
		End If
		Return Nothing
	End Function

	<System.Runtime.CompilerServices.Extension()> _
	Public Function ToImage(data As Byte()) As Image
		Dim result As Image = Nothing
		If data IsNot Nothing Then
			Using stream As New MemoryStream(data, 0, data.Length)
				result = Image.FromStream(stream)
			End Using
		End If
		Return result
	End Function
End Module

Module Globals
	Private _personAdapter As SqlDataAdapter
	Private _signatureAdapter As SqlDataAdapter
	Private ReadOnly _connection As SqlConnection = New SqlConnection("Data Source=.;Initial Catalog=EE_Q28962381;Integrated Security=True")

	Public ReadOnly Property [Connection]() As SqlConnection
		Get
			Return _connection
		End Get
	End Property

	Public ReadOnly Property [PersonAdapter]() As SqlDataAdapter
		Get
			If _personAdapter Is Nothing Then ConfigurePersonAdapter()
			Return _personAdapter
		End Get
	End Property

	Public ReadOnly Property [SignatureAdapter]() As SqlDataAdapter
		Get
			If _signatureAdapter Is Nothing Then ConfigureSignatureAdapter()
			Return _signatureAdapter
		End Get
	End Property

	Private Sub ConfigurePersonAdapter()
		_personAdapter = New SqlDataAdapter("SELECT * FROM PEOPLE", [Connection])
		_personAdapter.DeleteCommand = New SqlCommand("DELETE FROM PEOPLE WHERE ID = @ID", [Connection])
		_personAdapter.InsertCommand = New SqlCommand("INSERT INTO PEOPLE (NAME, BIRTHDATE, SIGNATUREID) OUTPUT INSERTED.IDENTITYCOL VALUES (@NAME, @BIRTHDATE, @SIGNATUREID)", [Connection])
		_personAdapter.UpdateCommand = New SqlCommand("UPDATE PEOPLE SET NAME = @NAME, BIRTHDATE = @BIRTHDATE, SIGNATUREID = @SIGNATUREID WHERE ID = @ID", [Connection])

		'' Configure the command parameters
		'' Delete Command
		_personAdapter.DeleteCommand.Parameters.Add("@ID", SqlDbType.Int)

		'' Insert Command
		_personAdapter.InsertCommand.Parameters.AddRange(New SqlParameter() {New SqlParameter("@NAME", SqlDbType.VarChar), New SqlParameter("@BIRTHDATE", SqlDbType.DateTime), New SqlParameter("@SIGNATUREID", SqlDbType.Int)})

		'' Update Command
		_personAdapter.UpdateCommand.Parameters.AddRange(New SqlParameter() {New SqlParameter("@NAME", SqlDbType.VarChar), New SqlParameter("@BIRTHDATE", SqlDbType.DateTime), New SqlParameter("@SIGNATUREID", SqlDbType.Int), New SqlParameter("@ID", SqlDbType.Int)})
	End Sub

	Private Sub ConfigureSignatureAdapter()
		_signatureAdapter = New SqlDataAdapter("SELECT * FROM SIGNATURES", [Connection])
		_signatureAdapter.DeleteCommand = New SqlCommand("DELETE FROM SIGNATURES WHERE ID = @ID", [Connection])
		_signatureAdapter.InsertCommand = New SqlCommand("INSERT INTO SIGNATURES (NAME, DATA) OUTPUT INSERTED.IDENTITYCOL VALUES (@NAME, @DATA)", [Connection])
		_signatureAdapter.UpdateCommand = New SqlCommand("UPDATE SIGNATURES SET NAME = @NAME, DATA = @DATA WHERE ID = @ID", [Connection])

		'' Configure the command parameters
		'' Delete Command
		_signatureAdapter.DeleteCommand.Parameters.Add("@ID", SqlDbType.Int)

		'' Insert Command
		_signatureAdapter.InsertCommand.Parameters.AddRange(New SqlParameter() {New SqlParameter("@NAME", SqlDbType.VarChar), New SqlParameter("@DATA", SqlDbType.VarBinary)})

		'' Update Command
		_signatureAdapter.UpdateCommand.Parameters.AddRange(New SqlParameter() {New SqlParameter("@NAME", SqlDbType.VarChar), New SqlParameter("@DATA", SqlDbType.VarBinary), New SqlParameter("@ID", SqlDbType.Int)})
	End Sub
End Module

Public Class Person
	Private _id As Integer = -1

	Public Property ID() As Integer
		Get
			Return _id
		End Get
		Set(ByVal value As Integer)
			_id = value
		End Set
	End Property

	Public Property Name() As String
	Public Property Birthdate() As DateTime
	<Browsable(False)> _
	Public Property SignatureID() As Integer
	Public Property Signature() As Image
End Class

Public Class Signature
	Private _id As Integer = -1

	Public Property ID() As Integer
		Get
			Return _id
		End Get
		Set(ByVal value As Integer)
			_id = value
		End Set
	End Property

	Public Property Name() As String
	Public Property Data() As Byte()
End Class

Open in new window


Produces the following output -

My initial load with data in the database:Capture.JPGRight-clicking an empty portion of the grid gives me the ability to add a person -Capture.JPGAdding a new person -Capture.JPGFilled in data (when OK is pressed the signature is stored in the database as a byte array)-Capture.JPGDatagrid updated (note that a thumbail of the signature is generated and displayed in the datagrid)-Capture.JPGChoosing to edit the person we just added -Capture.JPGThere data is reloaded from the database (including the signature) -Capture.JPGHere is the data structure in the database:Capture.JPG
The concepts should be approximately the same using the objects you have.

If you have any questions, please don't hesitate to ask.

-saige-
1
 

Author Comment

by:Mike B.
ID: 41753874
Thanks for the input! This is great. It's been rather busy so I'll try to apply it to my stuff this weekend. I'll let you know what happens on Monday.
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now