Не вызывайте CreateGraphics. В MouseDown сохраните начальную позицию и флаг, чтобы указать, что вы рисуете. В MouseMove проверьте флаг. Если вы рисуете, создайте прямоугольник относительно начальной позиции и сохраните его (что вы уже делаете), а затем вызовите Invalidate (). Весь ваш код для рисования будет в OnPaint () (canvas.Paint вне класса, хотя я бы, вероятно, создал свой собственный класс для этого, чтобы не засорять ваш код формы этим материалом).
Рисование должно быть сделано в вашем обработчике краски (OnPaint). Если вы рисуете за пределами этого, ваш графический объект не очищается (отсюда множество прямоугольников), и все, что вы рисуете на нем, может / будет стираться в, казалось бы, нечетные моменты, когда ваше окно получает сообщение WM_PAINT.
РЕДАКТИРОВАТЬ: Теперь, когда у вас проблемы с производительностью, есть несколько простых способов немного оптимизировать рисование. Во-первых, Invalidate может принять Rectangle в качестве аргумента, чтобы вам не пришлось перекрашивать весь элемент управления. Во-вторых, если вы рисуете в MouseMove, вы будете рисовать совсем немного. Использование двойной буферизации также очень поможет, просто установите для свойства DoubleBuffered значение true или добавьте его к значению ControlStyles, вызвав SetStyle для элемента управления.