Reputation: 691
I've implemented inking code in my app based on the simplified inking sample by microsoft : http://code.msdn.microsoft.com/windowsapps/Input-simplified-ink-sample-11614bbf/view/SourceCode
First I made a class that saves data of an operation (draw/delete/clear) like this:
public enum eInkOperation
{
Draw,
Delete,
None
}
public class InkOperation
{
public InkStroke Stroke { get; set; } //requred for drawing from undo
public eInkOperation Operation { get; set; }
public InkOperation(InkStroke stroke, eInkOperation inkOperation)
{
Stroke = stroke.Clone(); //needs to be cloned for AddStroke to work
Operation = inkOperation;
}
}
Then I made one stack for undo ink operations and one for redo operations
//stack of normal operations
Stack<InkOperation> _undoStack = new Stack<InkOperation>();
//Undo action will pop them off of the undo stack and push them onto the redo stack
Stack<InkOperation> _redoStack = new Stack<InkOperation>();
When a user undoes a stroke I push it on the redo stack and delete it from the inkmanager with these methods:
private void RedoStackPush(InkOperation inkOperation)
{
inkOperation.Stroke = inkOperation.Stroke.Clone();
_redoStack.Push(inkOperation);
}
private void DeleteStroke(InkStroke stroke)
{
stroke = inkManager.GetStrokes().Last();
stroke.Selected = true;
inkManager.DeleteSelected();
}
Then when the user clicks on redo, the stroke is popped off the redo stack and drawn using this method:
private void DrawStroke(InkStroke stroke)
{
if (stroke!=null)
{
inkManager.Mode = InkManipulationMode.Inking;
inkManager.AddStroke(stroke);
}
renderer.Clear(); //this renderer object smooths the strokes
//and adds them as Path objects to the desired control (Grid, etc)
renderer.AddInk(inkManager.GetStrokes());
}
This all works, and the stroke is displayed back on the grid. However, when I try to erase the newly redrawn stroke I get this exception:
AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
This happens in:
public void PointerMoved(PointerRoutedEventArgs e)
{
try
{
var pointerPoint = e.GetCurrentPoint(_inkingArea);
var pointerEventType = InkHelpers.GetPointerEventType(e);
if (pointerId == (int)pointerPoint.PointerId)
{
switch (inkManager.Mode)
{
case InkManipulationMode.Inking:
case InkManipulationMode.Selecting:
//process intermediate points
var intermediatePoints = e.GetIntermediatePoints(_inkingArea);
for (int i = intermediatePoints.Count - 1; i >= 0; i--)
{
inkManager.ProcessPointerUpdate(intermediatePoints[i]);
}
//live rendering
renderer.UpdateLiveRender(pointerPoint);
break;
case InkManipulationMode.Erasing:
//check if something has been erased
//in erase mode InkManager.ProcessPointerUpdate returns an invalidate rectangle:
//if it is not degenerate, something has been erased
//in erase mode don't bother processing intermediate points
//If inkManager.ProcessPointerUpdate throws an exception, it crashes the app regardless of any catches
Rect invalidateRect = (Rect)inkManager.ProcessPointerUpdate(e.GetCurrentPoint(_inkingArea));
if (invalidateRect.Height != 0 && invalidateRect.Width != 0)
{
//we don't know what has been erased so we clear the render
//and add back all the ink saved in the ink manager
renderer.Clear();
var remainingStrokes = inkManager.GetStrokes();
renderer.AddInk(remainingStrokes);
}
break;
default:
break;
}
}
}
catch (Exception) { }
}
At this line:
Rect invalidateRect = (Rect)inkManager.ProcessPointerUpdate(e.GetCurrentPoint(_inkingArea));
I think the problem lies in the process of adding strokes to the ink manager. I tried making a new stroke and even inheriting from the InkStroke to make it customizable but the InkStroke class is sealed and it doesn't have a constructor. The only was I found to copy it was to do inkStroke.Clone(). But even that has its problems when trying to redraw deleted ink (undo a deleted stroke).
I tried to make this question as clear as possible using the least amount of code to avoid confusion, so let me know if it's insufficient.
Also in this question I'm focusing on undoing a draw action. Undoing an erasing action (or even "clear all" action) has its own set of problems because I can't make a copy of the InkStroke object.
Thanks in advance for your time and consideration.
Upvotes: 2
Views: 1594