you have too many variables, this is called data redundancy. In particular you have both x,y,width,height and rect; in some parts you operate on x,y in others on rect.X and rect.Y, and that is why it does not behave as you would hope.
The rule is: avoid redundancy; there isn't anything positive about redundancy, it adds variables and code, and it just makes it harder to pinpoint logic errors.
Using a separate class helps in achieving this, or at least makes it harder to break the rule.
To make matters worse, you change your data model (your "business logic") inside the Paint handler, where it says
You should never modify your business model inside a Paint handler; a Paint handler should behave as an observer, and not as a participant.
Reason: you don't know when a Paint handler will be executed:
(a) calling Invalidate tells the system your business model has changed and a repaint is required, so a repaint message is queued, but not executed right away (e.g. several calls to Invalidate may result in a single repaint);
(b) a Paint handler will also run when something happened to your window, e.g. when a pop-up dialog (may be from another app or from Windows itself) temporarily had hidden (part of) your window.
The only kind of variables your Paint handler should ever modify are the ones that are needed by the Paint handler itself, so it would be OK to write
if (pen==null) pen=new Pen(Color.Red); assuming
pen isn't part of your business stuff.
I counted the number of lines in your code and mine, excluding empty lines, lines with a single bracket, comments, and Console.WriteLine lines; my code (Form+Rect) is 43 lines, yours 50. Which tells me using a class is the right way to go: it does not add to the code, and it supports what is known as "separation of concerns": let each piece of code take care of what matters to it without being troubled with details that don't matter there. Example: my form tells the Rect to paint itself or to move itself without caring how that is done, whereas the Rect knows how to paint or move itself without knowing why it should.
modified 29-Apr-20 9:01am.