我已经根据 microsoft 的简化墨迹示例在我的应用程序中实现墨迹代码:http: //code.msdn.microsoft.com/windowsapps/Input-simplified-ink-sample-11614bbf/view/SourceCode
首先,我创建了一个类来保存操作(绘制/删除/清除)的数据,如下所示:
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;
}
}
然后我做了一个堆栈用于撤消墨迹操作和一个用于重做操作
//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>();
当用户撤消笔画时,我将其推送到重做堆栈并使用以下方法从 inkmanager 中删除它:
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();
}
然后,当用户单击重做时,笔划会从重做堆栈中弹出并使用以下方法绘制:
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());
}
这一切都奏效了,笔画又显示在网格上。但是,当我尝试擦除新重绘的笔画时,我得到了这个异常:
AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
这发生在:
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) { }
}
在这一行:
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.