How to: Erase Ink in an InkPresenter

Microsoft Silverlight will reach end of support after October 2021. Learn more.

Silverlight does not have specific types and methods to erase ink strokes after they have been collected or loaded. However, you can use the HitTest and HitTest methods to implement erasing. Both of these methods take a StylusPointCollection collection as an input and return a value that indicates whether the ink strokes intersect with the collection. Based on the return value, you can then modify your ink strokes collection to perform an erase. Two common erase modes are stroke erase and point erase.

The code snippets in this topic are a part of a larger example. You can download the complete example from the following location.

Run this sample

Download this sample

Prerequisites

This topic assumes that you understand how to collect ink in an InkPresenter control as discussed in the Ink Overview topic.

Stroke Erase

Stroke erase deletes an entire stroke. For example, a mouse or stylus path that intersects with a stroke can initiate a stroke erase. You can implement a stroke erase by passing the StylusPointCollection collected by the mouse or stylus path to the HitTest method of your collection of ink strokes. The return value will indicate which stroke has to be removed from the collection.

The following steps describe how you can implement a stroke erase algorithm. In this algorithm, the user clicks the left mouse button or stylus and moves the pointer over a stroke to erase the stroke.

To implement stroke erase

  1. In the MouseLeftButtonDown event handler, collect the stylus points and store them in a StylusPointCollection object.

    void _presenter_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (_mode == InkMode.StrokeErase)
        {
            _erasePoints = e.StylusDevice.GetStylusPoints(_presenter);
        }
    }
    
    Private Sub _presenter_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs) 
        If _mode = InkMode.StrokeErase Then 
            _erasePoints = e.StylusDevice.GetStylusPoints(_presenter) 
        End If 
    End Sub
    
  2. In the MouseMove event handler, add the stylus points to the StylusPointCollection object created in the previous step (_erasePoints). Compare the collected stylus points with the stroke collection of the InkPresenter element by using the HitTest method. Delete the strokes returned by the HitTest method by using the Remove method.

    void _presenter_MouseMove(object sender, MouseEventArgs e)
    {
        if (_mode == InkMode.StrokeErase && _erasePoints != null)
        {
            _erasePoints.Add(e.StylusDevice.GetStylusPoints(_presenter));
    // Compare the collected stylus points with the stroke collection of the ink presenter.
            StrokeCollection hitStrokes = _presenter.Strokes.HitTest(_erasePoints);
    //Delete the strokes that intersect with the collected stylus points.
            if (hitStrokes.Count > 0)
            {
                foreach (Stroke hitStroke in hitStrokes)
                {
                    _presenter.Strokes.Remove(hitStroke);
                }
            }
        }
     }
    
    Private Sub _presenter_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) 
        If _mode = InkMode.StrokeErase AndAlso _erasePoints IsNot Nothing Then 
            _erasePoints.Add(e.StylusDevice.GetStylusPoints(_presenter)) 
            ' Compare the collected stylus points with the stroke collection of the ink presenter. 
            Dim hitStrokes As StrokeCollection = _presenter.Strokes.HitTest(_erasePoints) 
            'Delete the strokes that intersect with the collected stylus points. 
            If hitStrokes.Count > 0 Then 
                For Each hitStroke As Stroke In hitStrokes 
                    _presenter.Strokes.Remove(hitStroke) 
                Next 
            End If 
        End If 
    End Sub
    

Point Erase

Point erase deletes only part of a stroke. The implementation of point erase is similar to stroke erase. However, with point erase, a stroke that intersects with a mouse or stylus path is replaced by two strokes.

The following steps describe how you can implement a point erase algorithm. In this algorithm, the user clicks the left mouse button or stylus and moves the pointer over a stroke to split the stroke into two strokes.

To implement point erase

  1. In the MouseLeftButtonDown event handler, collect the stylus points and store them in a StylusPointCollection object. Store the last stylus point in this stylus point collection separately. Storing the last stylus point ensures that the point at which the mouse left button down event was called is also processed in the subsequent mouse move handler.

    void _presenter_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (_mode == InkMode.PointErase)
        {
            StylusPointCollection pointErasePoints = e.StylusDevice.GetStylusPoints(_presenter);
            //Store the last point in the stylus point collection.
            _lastPoint = pointErasePoints[pointErasePoints.Count-1];
        }
    }
    
    Private Sub _presenter_MouseLeftButtonDown(ByVal sender As Object, ByVal e As MouseButtonEventArgs) 
        If _mode = InkMode.PointErase Then 
            Dim pointErasePoints As StylusPointCollection = e.StylusDevice.GetStylusPoints(_presenter) 
            'Store the last point in the stylus point collection. 
            _lastPoint = pointErasePoints(pointErasePoints.Count - 1) 
        End If 
    End Sub 
    
  2. In the MouseMove event handler, add the stylus points to the StylusPointCollection object created in the previous step. Compare the collected stylus points with the stroke collection of the InkPresenter element by using the HitTest method and store the intersecting strokes. Remove the intersection of points between the stroke and the mouse or stylus path. The removal of the intersecting points is implemented in the ProcessPointErase method in the next step.

    void _presenter_MouseMove(object sender, MouseEventArgs e)
    {
        if (_mode == InkMode.PointErase && _lastPoint != null)
        {
            StylusPointCollection pointErasePoints = e.StylusDevice.GetStylusPoints(_presenter);
            pointErasePoints.Insert(0, _lastPoint.Value);
    //Compare collected stylus points with the ink presenter strokes and store the intersecting strokes.
            StrokeCollection hitStrokes = _presenter.Strokes.HitTest(pointErasePoints);
            if (hitStrokes.Count > 0)
            {
                foreach (Stroke hitStroke in hitStrokes)
                {
    //For each intersecting stroke, split the stroke into two while removing the intersecting points.
                    ProcessPointErase(hitStroke, pointErasePoints);
                }
            }
            _lastPoint = pointErasePoints[pointErasePoints.Count - 1];
        }
    }
    
    Private Sub _presenter_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) 
        If _mode = InkMode.PointErase AndAlso _lastPoint IsNot Nothing Then 
            Dim pointErasePoints As StylusPointCollection = e.StylusDevice.GetStylusPoints(_presenter) 
            pointErasePoints.Insert(0, _lastPoint.Value) 
            'Compare collected stylus points with the ink presenter strokes and store the intersecting strokes. 
            Dim hitStrokes As StrokeCollection = _presenter.Strokes.HitTest(pointErasePoints) 
            If hitStrokes.Count > 0 Then 
                For Each hitStroke As Stroke In hitStrokes 
                    'For each intersecting stroke, split the stroke into two while removing the intersecting points. 
                    ProcessPointErase(hitStroke, pointErasePoints) 
                Next 
            End If 
            _lastPoint = pointErasePoints(pointErasePoints.Count - 1) 
        End If 
    End Sub
    
  3. Implement the ProcessPointErase method to replace the intersecting stroke with two strokes. The ProcessPointErase method takes a Stroke named stroke and a StylusPointCollection named pointErasePoints as input and removes the intersecting points from the InkPresenter. Determine the intersection by starting with the first point on stroke and add each stylus point on stroke to splitStroke1 until a stylus point that intersects with pointErasePoints is reached. Repeat the process by starting with the last point on stroke and add each stylus point to splitStroke2 until a stylus point that intersects with the input pointErasePoints is reached. Finally, replace stroke with splitStroke1 and splitStroke2. You can do this by using the remove method and adding splitstroke1 and splitstroke2 to the InkPresenter.

    void ProcessPointErase(Stroke stroke, StylusPointCollection pointErasePoints)
    {
        Stroke splitStroke1, splitStroke2, hitTestStroke;            
    
        // Determine first split stroke.
        splitStroke1 = new Stroke();
        hitTestStroke = new Stroke();
        hitTestStroke.StylusPoints.Add(stroke.StylusPoints);
        hitTestStroke.DrawingAttributes = stroke.DrawingAttributes;
        //Iterate through the stroke from index 0 and add each stylus point to splitstroke1 until 
        //a stylus point that intersects with the input stylus point collection is reached.
        while (true)
        {
            StylusPoint sp = hitTestStroke.StylusPoints[0];
            hitTestStroke.StylusPoints.RemoveAt(0);
            if (!hitTestStroke.HitTest(pointErasePoints)) break;
            splitStroke1.StylusPoints.Add(sp);
        }
    
        // Determine second split stroke.
        splitStroke2 = new Stroke();
        hitTestStroke = new Stroke();
        hitTestStroke.StylusPoints.Add(stroke.StylusPoints);
        hitTestStroke.DrawingAttributes = stroke.DrawingAttributes;
        while (true)
        {
            StylusPoint sp = hitTestStroke.StylusPoints[hitTestStroke.StylusPoints.Count - 1];
            hitTestStroke.StylusPoints.RemoveAt(hitTestStroke.StylusPoints.Count - 1);
            if (!hitTestStroke.HitTest(pointErasePoints)) break;
            splitStroke2.StylusPoints.Insert(0, sp);
        }
    
        // Replace stroke with splitstroke1 and splitstroke2.
        if (splitStroke1.StylusPoints.Count > 1)
        {
            splitStroke1.DrawingAttributes = stroke.DrawingAttributes;
            _presenter.Strokes.Add(splitStroke1);
        }
        if (splitStroke2.StylusPoints.Count > 1)
        {
            splitStroke2.DrawingAttributes = stroke.DrawingAttributes;
            _presenter.Strokes.Add(splitStroke2);
        }
        _presenter.Strokes.Remove(stroke);
    }
    
    Private Sub ProcessPointErase(ByVal stroke As Stroke, ByVal pointErasePoints As StylusPointCollection) 
        Dim splitStroke1 As Stroke, splitStroke2 As Stroke, hitTestStroke As Stroke 
    
        ' Determine first split stroke. 
        splitStroke1 = New Stroke() 
        hitTestStroke = New Stroke() 
        hitTestStroke.StylusPoints.Add(stroke.StylusPoints) 
        hitTestStroke.DrawingAttributes = stroke.DrawingAttributes 
        'Iterate through the stroke from index 0 and add each stylus point to splitstroke1 until 
        'a stylus point that intersects with the input stylus point collection is reached. 
        While True 
            Dim sp As StylusPoint = hitTestStroke.StylusPoints(0) 
            hitTestStroke.StylusPoints.RemoveAt(0) 
            If Not hitTestStroke.HitTest(pointErasePoints) Then 
                Exit While 
            End If 
            splitStroke1.StylusPoints.Add(sp) 
        End While 
    
        ' Determine second split stroke. 
        splitStroke2 = New Stroke() 
        hitTestStroke = New Stroke() 
        hitTestStroke.StylusPoints.Add(stroke.StylusPoints) 
        hitTestStroke.DrawingAttributes = stroke.DrawingAttributes 
        While True 
            Dim sp As StylusPoint = hitTestStroke.StylusPoints(hitTestStroke.StylusPoints.Count - 1) 
            hitTestStroke.StylusPoints.RemoveAt(hitTestStroke.StylusPoints.Count - 1) 
            If Not hitTestStroke.HitTest(pointErasePoints) Then 
                Exit While 
            End If 
            splitStroke2.StylusPoints.Insert(0, sp) 
        End While 
    
        ' Replace stroke with splitstroke1 and splitstroke2. 
        If splitStroke1.StylusPoints.Count > 1 Then 
            splitStroke1.DrawingAttributes = stroke.DrawingAttributes 
            _presenter.Strokes.Add(splitStroke1) 
        End If 
        If splitStroke2.StylusPoints.Count > 1 Then 
            splitStroke2.DrawingAttributes = stroke.DrawingAttributes 
            _presenter.Strokes.Add(splitStroke2) 
        End If 
        _presenter.Strokes.Remove(stroke) 
    End Sub
    

See Also

Reference

Concepts