Question User Control Graphics

Clifton

New member
Joined
Apr 24, 2021
Messages
1
Programming Experience
10+
I am new to Visual Studio 2019 VB.Net but had many years programming in the past before I retired in 2010. Much has changed since VB6 but I am catching on fast. To the Point: I have created a user control which is a Graph. The Graph Graphics are complete and everything works fine. The Problem I am encountering is How to give the user a Graphical Interface to the control so he or she can also draw graphics to the control from a form that is parent to the control. In the past (VB6) we had to create custom subs or functions that handled the graphics from the user. The main problem is keeping the Graphics persistent when a new paint event is fired. I have researched Control.OnPaint Method and EventHandler Method. The Problem I am Having using these methods is letting the user pass argument for a method such as arguments for drawing a line these Arguments. In short How to let the user call a sub on the control that then draws graphics on the control and still has persistent paint event?

I hope some can maybe start me off in the correct direction Please!
 
Last edited by a moderator:
WinForms graphics is pretty simple when you get the basic concepts. You need to do ALL your drawing on each Paint event. If your code is in a form and you want to draw on a child control then that means handling that control's Paint event and putting your drawing code in the event handler. In a control that draws on itself, you override the OnPaint event and put the same code there. It is the base implementation of OnPaint that actually invokes any registered event handler. That means that anything you put before the call to the base method gets drawn before anything in an event handler, i.e. underneath, and anything you put after that call gets drawn after, i.e. on top.

You should store the data that represents your drawing in one or more member variables. Your drawing code then gets that data and uses it to draw whatever is appropriate. For instance, you might have a field that refers to a List(Of Tuple(Of Point, Point)), where each item in the list is a pair of points representing the start and end of a line. Your drawing code would then loop over that list and call e.Graphics.DrawLine with each pair of Point values.

As I said, your code needs to do ALL the drawing every time. That part is actually fast. The slow part of the process is the actual painting of pixels on the screen. For that reason, you want to keep that painting to a minimum. Whenever an area of your control has or may have changed, you should invalidate it. You can invalidate as many separate areas as you like and then, on the next Paint event, all invalidated are will be repainted with the result of your drawing code. It is worth writing code that may seem somewhat complex in order to keep the invalidated area to a minimum because executing that code is still faster than painting the extra area that doing so will exclude. For instance, using my previous example of a collection of lines, if you were to add a new line to the list, you could calculate the smallest Rectangle that contained that line and then pass that as an argument to Invalidate. That will record that area as needing to be repainted and queue a Paint event. Once the UI thread has finished doing what it's doing, it will then execute your drawing code to draw everything, then repaint the invalidated area of the control and the new line will appear in that area. The same goes if you were to remove a line, i.e. invalidate that area and execute your drawing code and then that area will get repainted without that line.

Calculating a Rectangle is easy to do based on minimum and maximum X and Y coordinates. If your area is more complex though, it might be appropriate to calculate multiple Rectangles and call Invalidate multiple times or create a single Region and pass that to Invalidate instead.
 
Back
Top