1、InkCanvas类。

实现画板需要用到InkCanvas。一般情况下不需任何代码就可以在上面画线了。

如果需要设置画笔颜色、笔尖大小等就需要设置DefaultDrawingAttributes,例如:

DrawingAttributes attributes = new DrawingAttributes();
attributes.Color = Colors.Black;
attributes.Height = 50;
attributes.Width = 50;
attributes.FitToCurve = true;

2、在InkCanvas上画直线

方法:在StrokeCollected事件中进行修正,StrokeCollected事件在单个笔画结束后触发。可以取出笔画的起始点(BeginPoint)和终点(EndPoint),然后使用该两点新建笔画即可。

代码如下:

private void InkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
    {
        if (e.Stroke.StylusPoints.Count > 1)
        {
            UpdateLine(e.Stroke);
        }
    }
private void UpdateLine(Stroke currentStroke)
    {
        StylusPoint beginPoint = currentStroke.StylusPoints[0];//起始点
        StylusPoint endPoint = currentStroke.StylusPoints.Last();//终点
        packageCanvas.Strokes.Remove(currentStroke);//移除原来的笔画
        List<Point> pointList = new List<Point>();
        pointList.Add(new Point(beginPoint.X, beginPoint.Y));
        pointList.Add(new Point(endPoint.X, endPoint.Y));
        StylusPointCollection point = new StylusPointCollection(pointList);
        Stroke stroke = new Stroke(point);//用两点实现笔画
        stroke.DrawingAttributes = packageCanvas.DefaultDrawingAttributes.Clone();
        InkCanvas.Strokes.Add(stroke);           
}

3、在InkCanvas上画直虚线

方法:还是跟上面一样取起始点和终点,不同点是:在两点间绘制许多点,然后将相邻的两点连接成一个笔画。这样一个直虚线变好了。

代码如下:

private void UpdateLine(Stroke currentStroke)
{

       InkCanvas.Strokes.Remove(currentStroke);//移除原来笔画 int dotTime = 0;

            int intervalLen=6;//步长
            double lineLen = Math.Sqrt(Math.Pow(beginPoint.X - endPoint.X, 2) + Math.Pow(beginPoint.Y - endPoint.Y, 2));//线的长度
            Point currentPoint = new Point(beginPoint.X, beginPoint.Y);
            double relativaRate = Math.Abs(endPoint.Y - beginPoint.Y) * 1.0 / Math.Abs(endPoint.X - beginPoint.X);
            double angle = Math.Atan(relativaRate) * 180 / Math.PI;//直线的角度大小,无需考虑正负
            int xOrientation = endPoint.X > beginPoint.X ? 1 : -1;//判断新生成点的X轴方向
            int yOrientation = endPoint.Y > beginPoint.Y ? 1 : -1;
            if (lineLen < intervalLen)
            {
                return;
            }
            while (dotTime * intervalLen < lineLen)
            {
                double x = currentPoint.X + dotTime * intervalLen * Math.Cos(angle * Math.PI / 180) * xOrientation;
                double y = currentPoint.Y + dotTime * intervalLen * Math.Sin(angle * Math.PI / 180) * yOrientation; 
                List<Point> pL = new List<Point>();
                pL.Add(new Point(x, y));
                x += intervalLen * Math.Cos(angle * Math.PI / 180) * xOrientation;
                y += intervalLen * Math.Sin(angle * Math.PI / 180) * yOrientation;
                pL.Add(new Point(x, y));
                StylusPointCollection spc = new StylusPointCollection(pL);//相邻两点作为一个笔画
                Stroke stroke = new Stroke(spc);
                stroke.DrawingAttributes = packageCanvas.DefaultDrawingAttributes.Clone();
                InkCanvas.Strokes.Add(stroke);
                dotTime+=2;
            }
}

4、在InkCanvas上画弯虚线

方法:在InkCanvas_StrokeCollected方法的参数属性中可以获得线上的点的坐标。

2)生成StylusPointCollection collection=currentStroke.StylusPoints,用来存放当前笔画的所有点

2)生成一个List allPointList,用来存放最终生成的点

2) 将起始点=》allPointList,起始点-》currentPoint

3)遍历collection,IF currentPoint与找到点(item)的距离==步长 THEN item=>allPointList;item=>currentPoint,取下一个点

IF currentPoint与找到点(item)的距离>步长 THEN 在currentPoint与item线上找到一个点,使得与currentPoint的距离=步长,item=>allPointList;item=>currentPoint,继续当前点

IF currentPoint与找到点(item)的距离<步长 取下一个点

代码如下:

private void UpdateLine(Stroke currentStroke)
{
InkCanvas.Strokes.Remove(currentStroke);
            StylusPointCollection collection = currentStroke.StylusPoints;
            List<Point> allSelectedPoint = new List<Point>();
            Point currentPoint = new Point(collection[0].X, collection[0].Y);
            allSelectedPoint.Add(currentPoint);
            for (int i = 0; i < collection.Count; i++)
            {
                var item = collection[i];
                double length = Math.Sqrt(Math.Pow(item.X - currentPoint.X, 2) + Math.Pow(item.Y - currentPoint.Y, 2));
                if ((int)(length + 0.5) == (int)intervalLen || length == intervalLen)
                {

                    currentPoint = new Point(item.X, item.Y);
                    allSelectedPoint.Add(currentPoint);
                }
                else if (length > intervalLen)
                {
                    double relativaRate = Math.Abs(item.Y - currentPoint.Y) * 1.0 / Math.Abs(item.X - currentPoint.X);
                    double angle = Math.Atan(relativaRate) * 180 / Math.PI;
                    int xOrientation = item.X > currentPoint.X ? 1 : -1;
                    int yOrientation = item.Y > currentPoint.Y ? 1 : -1;
                    double x = currentPoint.X + intervalLen * Math.Cos(angle * Math.PI / 180) * xOrientation;
                    double y = currentPoint.Y + intervalLen * Math.Sin(angle * Math.PI / 180) * yOrientation;
                    currentPoint = new Point(x, y);
                    allSelectedPoint.Add(currentPoint);
                    i--;//很重要,继续当前点
                }
            }
            for (int j = 0; j < allSelectedPoint.Count; j++)
            {
                List<Point> p = new List<Point>();
                p.Add(allSelectedPoint[j]);
                if (j < allSelectedPoint.Count - 1)
                {
                    j++;
                }
                p.Add(allSelectedPoint[j]);
                StylusPointCollection spc = new StylusPointCollection(p);
                Stroke stroke = new Stroke(spc);
                InkCanvas.Strokes.Add(stroke);
            }
}

以上是测试过的代码,不足之处是:只能在当前笔画完成后在进行修正,因为代码写在InkCanvas_StrokeCollected中。

知识共享许可协议
《WPF中的画笔功能,实现直实线、弯实线、直虚线、弯虚线》 常伟华 创作。
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议 | 3.0 中国大陆许可协议进行许可。

站内公告