Tablet PC: Overview of InkAnaysis events


The InkAnalysis API exposes functionality for both layout analysis (parsing) of ink, and the handwriting recognition for that ink as well. The InkAnalyzer class has several events that can be hooked up to in order to perform different tasks. For a complete list of events and brief descriptions of those events, see the example code below.


 


Consider the simple example where you write a word, then circle that word, add the strokes that make up that ink to an InkAnalyzer, then call BackgroundAnalyze(). What events would get fired? Here is actual output from the sample application (example code below) when run for this scenario: (Blue indicates parsing stage, red indicates recognition stage)


 






Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


Activity event fired


InkAnalyzerStateChanging event fired


ContextNodeCreated event fired


ContextNodeMovingToPosition event fired


StrokesReparented event fired


ContextNodeCreated event fired


ContextNodeMovingToPosition event fired


ContextNodeCreated event fired


ContextNodeCreated event fired


ContextNodeCreated event fired


StrokesReparented event fired


ContextNodeDeleting event fired


ContextNodeLinkAdding event fired


ContextNodePropertiesUpdated event fired


ContextNodePropertiesUpdated event fired


ContextNodePropertiesUpdated event fired


ContextNodePropertiesUpdated event fired


ContextNodePropertiesUpdated event fired


IntermediateResultsUpdated event fired


Activity event fired


Activity event fired


InkAnalyzerStateChanging event fired


ContextNodePropertiesUpdated event fired


ResultsUpdated event fired


 


 


Screenshot of application running:

screenshot

 


Example code:






 //


// Basic Ink enabled Windows Forms application with


// handwriting recognition using InkAnalyzer


// Gavin Gear - http://blogs.msdn.com/gavingear


// 09/2006


//


 


using System;


using System.Collections.Generic;


using System.ComponentModel;


using System.Data;


using System.Drawing;


using System.Text;


using System.Windows.Forms;


 


using Microsoft.Ink; // The managed Tablet PC API


 


namespace BasicInkApplication


{


    public partial class BasicInkApplication : Form


    {


        // The InkOverlay that we'll attach to our Form


        private InkOverlay inkOverlay;


        private InkAnalyzer inkAnalyzer;


        private string eventsString = "";


 


        public BasicInkApplication()


        {


            InitializeComponent();


 


            // Create an InkOverlay object that's attached to the Form


            this.inkOverlay = new InkOverlay(this);


            // Enable the InkOverlay (default is Enabled == false)


            this.inkOverlay.Enabled = true;


            this.inkOverlay.Stroke += new InkCollectorStrokeEventHandler(inkOverlay_Stroke);


 


            // Create a new InkAnalyzer


            // - Associate with the InkOverlay's Ink object


            // - Send the Form "this" as the synchronizing object


            this.inkAnalyzer = new InkAnalyzer(this.inkOverlay.Ink, this);


 


            // Indicates analysis activity - can use to indicate progress


            this.inkAnalyzer.Activity += new ActivityEventHandler(inkAnalyzer_Activity);


           


            // A ContextNode was created- Example: An InkWordNode was created as the result of Analysis


            this.inkAnalyzer.ContextNodeCreated += new ContextNodeCreatedEventHandler(inkAnalyzer_ContextNodeCreated);


 


            // A ContextNode was deleted- Exmaple: An InkWordNode is deleted because the user deleted the


            // corresponding strokes from the ink collection surface


            this.inkAnalyzer.ContextNodeDeleting += new ContextNodeDeletingEventHandler(inkAnalyzer_ContextNodeDeleting);


 


            // A ContextLink is added - example: A circle was drawn around a word - a ContextLink is created indicating


            // that the drawing (circle) encloses the InkWordNode


            this.inkAnalyzer.ContextNodeLinkAdding += new ContextNodeLinkAddingEventHandler(inkAnalyzer_ContextNodeLinkAdding);


 


            // A ContextLink is removed - example: A circle enclosing a word is deleted by the user


            this.inkAnalyzer.ContextNodeLinkDeleting += new ContextNodeLinkDeletingEventHandler(inkAnalyzer_ContextNodeLinkDeleting);


 


            // A ContextNode is moved to a different position under the same parent - example: the strokes comprising


            // a word are moved by the user horizontally changing the word ordering within a line


            this.inkAnalyzer.ContextNodeMovingToPosition += new ContextNodeMovingToPositionEventHandler(inkAnalyzer_ContextNodeMovingToPosition);


           


            // A ContextNode's property was updated - see ContextNode documentation for more detail


            this.inkAnalyzer.ContextNodePropertiesUpdated += new ContextNodePropertiesUpdatedEventHandler(inkAnalyzer_ContextNodePropertiesUpdated);


           


            // A ContextNode is moved to another parent - example: The strokes comprising a line were moved from one


            // paragraph to another paragraph my the user


            this.inkAnalyzer.ContextNodeReparenting += new ContextNodeReparentingEventHandler(inkAnalyzer_ContextNodeReparenting);


           


            // The InkAnalyzer is about to integrate results from analysis with it's internal data structure


            // the application can synchronise to the data structure at this time


            this.inkAnalyzer.InkAnalyzerStateChanging += new InkAnalyzerStateChangingEventHandler(inkAnalyzer_InkAnalyzerStateChanging);


           


            // Layout analysis is complete (parsing) the ContextNodes, ContextLinks, etc are in place


            // this event is fired before the recognition stage is started


            this.inkAnalyzer.IntermediateResultsUpdated += new ResultsUpdatedEventHandler(inkAnalyzer_IntermediateResultsUpdated);


           


            // New strokes were loaded into the InkAnalyzer via InkAnalyzer.Load()


            this.inkAnalyzer.NewStrokesLoaded += new NewStrokesLoadedEventHandler(inkAnalyzer_NewStrokesLoaded);


 


            // A partially populated ContextNode needs to be populated with data before analysis can continue


            // this is part of an advanced topic called DataProxy whereby an application's data can be


            // synchronized with the InkAnalyzer on an as-needed basis


            this.inkAnalyzer.PopulateContextNode += new PopulateContextNodeEventHandler(inkAnalyzer_PopulateContextNode);


           


            // If automatic reconciliation is disabled, Reconcile() should be called from this event handler


            this.inkAnalyzer.ReadyToReconcile += new ReadyToReconcileEventHandler(inkAnalyzer_ReadyToReconcile);


 


            // Fired when background analysis is complete


            this.inkAnalyzer.ResultsUpdated += new ResultsUpdatedEventHandler(inkAnalyzer_ResultsUpdated);


 


            // Strokes were moved from one ContextNode to another


            this.inkAnalyzer.StrokesReparented += new StrokesReparentedEventHandler(inkAnalyzer_StrokesReparented);


 


            // The InkOverlay needs to be disposed due to unmanaged resources


            // used by the InkOverlay


            this.FormClosing += new FormClosingEventHandler(BasicInkApplication_FormClosing);


        }


 


        private void LogEvent(string EventName)


        {


            this.eventsString += EventName + " event fired" + Environment.NewLine;


        }


 


        void inkAnalyzer_StrokesReparented(object sender, StrokesReparentedEventArgs e)


        {


            LogEvent("StrokesReparented");


        }


 


        void inkAnalyzer_ResultsUpdated(object sender, ResultsUpdatedEventArgs e)


        {


            LogEvent("ResultsUpdated");


 


            // Since analysis is done, display the results...


            string result = this.inkAnalyzer.GetRecognizedString();


 


            MessageBox.Show(


                "Analysis complete, recognized string:" + Environment.NewLine +


                result + Environment.NewLine + Environment.NewLine +


                "Events that fired:" + Environment.NewLine +


                eventsString, "Analysis Summary");


 


        }


 


        void inkAnalyzer_ReadyToReconcile(object sender, EventArgs e)


        {


            LogEvent("ReadyToReconcile");


        }


 


        void inkAnalyzer_PopulateContextNode(object sender, PopulateContextNodeEventArgs e)


        {


            LogEvent("PopulateContextNode");


        }


 


        void inkAnalyzer_NewStrokesLoaded(object sender, NewStrokesLoadedEventArgs e)


        {


            LogEvent("NewStrokesLoaded");


        }


 


        void inkAnalyzer_IntermediateResultsUpdated(object sender, ResultsUpdatedEventArgs e)


        {


            LogEvent("IntermediateResultsUpdated");


        }


 


        void inkAnalyzer_InkAnalyzerStateChanging(object sender, EventArgs e)


        {


            LogEvent("InkAnalyzerStateChanging");


        }


 


        void inkAnalyzer_ContextNodeReparenting(object sender, ContextNodeReparentingEventArgs e)


        {


            LogEvent("ContextNodeReparenting");


        }


 


        void inkAnalyzer_ContextNodePropertiesUpdated(object sender, ContextNodePropertiesUpdatedEventArgs e)


        {


            LogEvent("ContextNodePropertiesUpdated");


        }


 


        void inkAnalyzer_ContextNodeMovingToPosition(object sender, ContextNodeMovingToPositionEventArgs e)


        {


            LogEvent("ContextNodeMovingToPosition");


        }


 


        void inkAnalyzer_ContextNodeLinkDeleting(object sender, ContextNodeLinkDeletingEventArgs e)


        {


            LogEvent("ContextNodeLinkDeleting");


        }


 


        void inkAnalyzer_ContextNodeLinkAdding(object sender, ContextNodeLinkAddingEventArgs e)


        {


            LogEvent("ContextNodeLinkAdding");


        }


 


        void inkAnalyzer_ContextNodeDeleting(object sender, ContextNodeDeletingEventArgs e)


        {


            LogEvent("ContextNodeDeleting");


        }


 


        void inkAnalyzer_ContextNodeCreated(object sender, ContextNodeCreatedEventArgs e)


        {


            LogEvent("ContextNodeCreated");


        }


 


        void inkAnalyzer_Activity(object sender, EventArgs e)


        {


            LogEvent("Activity");


        }


 


        void inkOverlay_Stroke(object sender, InkCollectorStrokeEventArgs e)


        {


            // We have a new stroke, add it to the InkAnalyzer


            this.inkAnalyzer.AddStroke(e.Stroke);


        }


 


        void BasicInkApplication_FormClosing(object sender, FormClosingEventArgs e)


        {


            this.inkOverlay.Dispose();


            this.inkAnalyzer.Dispose(); // Free the unmanaged resources


        }


 


        private void buttonRecognize_Click(object sender, EventArgs e)


        {


            this.eventsString = "";


 


            // Kick off asynchronous analysis


            this.inkAnalyzer.BackgroundAnalyze();


        }


 


 


    }


}


 


There’s a lot more that could be said regarding InkAnalysis events, but this gives you a basic idea of what events do in the InkAnalysis API.


 


See ya,


Gavin


Skip to main content