2

Microsoft による簡略化されたインキング サンプルに基づいて、アプリにインキング コードを実装しました。

最初に、次のような操作 (描画/削除/クリア) のデータを保存するクラスを作成しました。

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;
    }
}

次に、元に戻すインク操作用に 1 つのスタックを作成し、やり直し操作用に 1 つのスタックを作成しました。

//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>();

ユーザーがストロークを元に戻すと、次のメソッドを使用してストロークをやり直しスタックにプッシュし、インクマネージャーから削除します。

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));

問題は、インク マネージャーにストロークを追加するプロセスにあると思います。新しいストロークを作成し、InkStroke から継承してカスタマイズ可能にしようとしましたが、InkStroke クラスはシールされており、コンストラクターがありません。それをコピーすることがわかったのは、inkStroke.Clone() を実行することだけでした。しかし、削除されたインクを再描画しようとすると (削除されたストロークを元に戻す)、それでも問題があります。

混乱を避けるために最小限のコードを使用して、この質問をできるだけ明確にしようとしましたが、不十分な場合はお知らせください。

また、この質問では、描画アクションを元に戻すことに焦点を当てています。InkStroke オブジェクトのコピーを作成できないため、消去操作 (または「すべて消去」操作でさえも) を元に戻すには、独自の問題があります。

お時間をいただき、ご検討いただきありがとうございます。

4

1 に答える 1

1

MSDN のこのスレッドを参照してください。役立つ場合があります。

于 2013-03-22T10:59:08.003 に答える