Home > Net >  Performance problem of creating Strokes for an WPF InkCanvas programmatically
Performance problem of creating Strokes for an WPF InkCanvas programmatically

Time:10-27

I asked a question in Cancel touch event on InkCanvas (.Net Framework) and didn't got an answer, so I tried to set the InkCanvas to HitTestVisible to false and get the StylusPoints over an API of the driver. These points are now manually put into Strokes and then inside a bound StrokeCollection. This way, I get the points only from the stylus and not from touch or mouse (I know UWP InkCanvas can do this by default, but WPF is sadly too old and didn't got a correct support from Microsoft).

But I have a problem regarding the speed of this method. I make a Stroke out of every point (and the point before) and put them inside the StrokeCollection. This leads to a "slow" Stroke. If I write something it is only shown by around 3/4 when I already completed it with the pen and is then completly shown half a second later. Do you have any ideas on how to make this faster, so that it looks like a normal use of the InkCanvas? Alternatively the question from before could be answered ;)

This is my code:

private void TabLib_DataReceived(object sender, EventArgs e)
{
    float pressureFactor = e.pressure / 1024f;

    StylusPoint newPoint = new StylusPoint()
    {
        PressureFactor = pressureFactor,
        X = e.xPos,
        Y = e.yPos
    };

    if (pressureFactor == 0) // that means the pen has left or entered the tablet
    {
        _oldPressurePoint = newPoint;
        return;
    }

    StylusPointCollection pointList = new StylusPointCollection();
    pointList.Add(_oldPressurePoint);
    pointList.Add(newPoint);
    Stroke stroke = new Stroke(pointList, _penDrawingAttributes);
    // used a dispatcher begininvoke because of DrawnStrokes are bound to the UI thread.
    _tabletWindow.Dispatcher.BeginInvoke(new Action<Stroke>((newStroke) =>
    {
        DrawnStrokes.Add(newStroke); // DrawnStrokes is the bound StrokeCollection
    }), stroke);

    _oldPressurePoint = newPoint;
}

I also thought about creating one stroke and only add the points, but this seems not to work. If you already added a stroke, you cannot add points to this stroke, can you?

CodePudding user response:

You should create a new Stroke only when necessary, and add points to the StylusPoints collection of the current Stroke.

Here is a smoothly working example that creates stroke data from mouse input on a Canvas overlay over an InkCanvas.

<Grid>
    <InkCanvas x:Name="inkCanvas" IsHitTestVisible="False"/>
    <Canvas Background="Transparent"
            MouseLeftButtonDown="CanvasMouseLeftButtonDown"
            MouseLeftButtonUp="CanvasMouseLeftButtonUp"
            MouseMove="CanvasMouseMove"/>
</Grid>

with this code behind:

private Stroke stroke;

private void CanvasMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var pos = e.GetPosition(inkCanvas);
    var points = new StylusPointCollection
    {
        new StylusPoint(pos.X, pos.Y)
    };

    stroke = new Stroke(points, inkCanvas.DefaultDrawingAttributes);
    inkCanvas.Strokes.Add(stroke);
}

private void CanvasMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    stroke = null;
}

private void CanvasMouseMove(object sender, MouseEventArgs e)
{
    if (stroke != null)
    {
        var pos = e.GetPosition(inkCanvas);
        stroke.StylusPoints.Add(new StylusPoint(pos.X, pos.Y));
    }
}
  • Related