Draw multiple freehand Polyline or Curve drawing - Adding Undo Feature
You need to store lines in a List<List<Point>>
. Each element of the list contains points of a drawing which you draw using a down, move and up. The next line which you draw, will store in the next element of list. Each undo, will remove the last drawing.
Put an instance of this control on your form and it will handle the drawing for you. Also to perform undo, call its Undo
method.
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public class DrawingSurface : Control
{
public DrawingSurface() { this.DoubleBuffered = true; }
List<List<Point>> Lines = new List<List<Point>>();
bool drawing = false;
protected override void OnMouseDown(MouseEventArgs e) {
Lines.Add(new List<Point>());
Lines.Last().Add(e.Location);
drawing = true;
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e) {
if (drawing) { Lines.Last().Add(e.Location); this.Invalidate(); }
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e) {
if (drawing) {
this.drawing = false;
Lines.Last().Add(e.Location);
this.Invalidate();
}
base.OnMouseUp(e);
}
protected override void OnPaint(PaintEventArgs e) {
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
foreach (var item in Lines)
e.Graphics.DrawLines(Pens.Black, item.ToArray()); /*or DrawCurve*/
}
public void Undo() {
if (Lines.Count > 0) { this.Lines.RemoveAt(Lines.Count - 1); this.Invalidate(); }
}
}
Note
- Using this logic, you can simply implement redo using an other
List<List<Point>>
. It's enough to copy the last item before undo to redo list usingRedoBuffer.Add(Lines.Last());
. Then for each redo command, it's enough to add the last item of redo buffer toLines
and remove it from redo buffer. You should also clear the redo buffer after each mouse down. You can use either of
DrawLines
orDrawCurve
based on your requirement.DrawLines
draws a poly-line, whileDrawCurve
draws a more smooth curve.I prefer to encapsulate
Lines.Count > 0
in a property likebool CanUndo
and make it accessible from outside of control.It's just an example and you can simply extend the solution. For example, instead of
List<List<Point>>
you can create aShape
class containingList<Point>
,LineWidth
,LineColor
, etc and perform task usingList<Shape>
.