Introduction
Visual Studio provides powerful databinding features which allow you, the developer, to attach controls to fields in a database table and have those fields update automatically when the current record in the table is changed. What makes it so powerful is that you can do this with little or no code. With common data types like strings or numbers, databinding is very simple, but it gets slightly more complicated when the data to be bound to is a custom type. This article addresses that special case and discusses how to bind a control to ink stored in a database. Note that the ink I'm referring to is the ink from the Microsoft Tablet PC SDK.
This article is a companion article to Using .NET Databinding to Display Ink from a Database which discussed how to bind a read-only InkPicture
control to a database. If you have not read that article, you should probably take a moment to do so now. This article will go a step further and discuss how to create a read-write binding of the ink to the database using a control that is derived from the InkPicture
control and it assumes that you are familiar with all the content in the previous article. Due to threading issues it is not possible to create a read/write binding to the InkPicture
control directly, hence the need for us to create our own derived control.
Background
This article assumes that you have knowledge of or experience using bound controls in Microsoft Visual Studio and are able to use the IDE to manipulate Connections, DataAdapters, and DataSets. Basic understanding of the development of user controls is also helpful, but not necessary.
Using the code
In order to use the code in this article you will need to have the Microsoft Tablet PC SDK installed on your development machine. The Tablet PC SDK can be downloaded from http://www.microsoft.com/downloads/details.aspx?FamilyID=b46d4b83-a821-40bc-aa85-c9ee3d6e9699&displaylang=en. It is not necessary to have a Tablet PC in order to use the SDK.
Creating the Ink Control
Because of a threading issue with the InkPicture control that ships with the Tablet PC SDK it is necessary to crate our own InkPicture control to use in our databinding. We don't want to reinvent the wheel so we use inheritance and derive our new control from the InkPicture control. The code below shows what the declaration of our new control should look like.
public class InkDataPicture : Microsoft.Ink.InkPicture
{
}
The inherited control takes on all the properties and methods of the control it inherits from so we only need to implement the properties or methods that we would like to change. If you've done development with Ink serialization and the InkPicture box then you know that the InkEnabled property of the control needs to be false if you are going to manipulate the ink in code. We bind to the Ink property of the control using formatting events and those events do not provide us access to the source control; they only provide us access to the data. Because we don't have access to the control we cannot ensure that the InkEnabled property is false. Because of this issue, attempts to bind to an editable InkPicture box will fail.
To work around the editing limitation of the InkPicture control we will implement a new Ink property on our inherited control. In our property we will force the InkEnabled
property to be false whenever the Ink
property is written to. The code below shows this new property.
public new Ink Ink
{
get {return base.Ink;}
set
{
bool EnabledCache = base.InkEnabled;
base.InkEnabled = false;
base.Ink = value;
base.InkEnabled = EnabledCache;
}
}
Binding the Ink to the Control
In the previous article which described binding read-only ink to the control. The process is very similar for the read/write binding. The only difference is the addition of an event handler for the Parse
event. The Format
event fired when the data in the database (a byte array) needed to be converted to Ink. The Parse
event is the exact opposite and fires when the Ink needs to be converted back to bytes for storage in the database. The code below demonstrates how to bind the control to the database and implement the event handlers.
private void Form1_Load(object sender, System.EventArgs e)
{
Binding binding = inkDataPicture1.DataBindings.Add(
"Ink",myDS1,"MyTable.InkField");
binding.Format += new ConvertEventHandler(binding_Format);
binding.Parse += new ConvertEventHandler(binding_Parse);
odbDA.Fill(myDS1);
}
private void binding_Format(object sender, ConvertEventArgs e)
{
Ink ink = new Ink();
if (e.DesiredType.Equals(typeof(Ink)))
{
if (e.Value.GetType().Equals(typeof(byte[])))
{
byte[] bytes = (byte[])e.Value;
if (bytes.Length>0)
{
ink.Load(bytes);
}
}
e.Value = ink;
}
}
private void binding_Parse(object sender, ConvertEventArgs e)
{
if (e.DesiredType.Equals(typeof(byte[])) &&
e.Value.GetType().Equals(typeof(Ink)))
{
Ink ink = (Ink)e.Value;
e.Value = ink.Save(PersistenceFormat.InkSerializedFormat);
}
}
The code above allows you to make changes to the ink in your new control but the changes won't be saved to the database until you instruct it to. This is done in our sample application by the use of the Update
method on the DataAdapter
.
odbDA.Update(myDS1);
That's all there is too it. It's not quite as simple as standard databinding but once you have it working you could forget about it and never touch the code again.
For other easy to use, and free, ink-enabled controls visit our Web site at http://www.chickenscratchsoftware.com/.