Comic Book Guy
Comic Book Guy

Reputation: 119

mouse movements for background thread created windows forms

I am wondering if it is possible to 1) Hosting a background thread created windows form inside application main thread created windows form ? or 2) Separate the thread which processes mouse movements from the thread which is painting a windows form application ?

I know these questions sounds very crazy, but I find myself encountering a peculiar problem and I welcome advice of being able to side-step this problem, though I do not think we can part from windows forms and use different ui technology easily.

Our software team writes some plugins for a 3-rd party windows form application. SO we provide a root main form which hosts a bunch of user controls to them, using their api and they host them in their own windows form. Currently all user interfaces are created on the application's main thread, so they play nicely with each other. Many of our user controls we provide have system.windows.forms.datavisualisation charts, which are painted live by data the application is sourcing. One of the problem we have is when the user moves the mouse around erratically the display stop updating as all the painting of the graphs (GDI+) is done on the main thread ( we use background threads and TPL for sourcing and computing data, but painting is done on the main thread). So I am wondering if it is possible to make all the gdi+ painting of these charts occur on a different thread than the application main thread, so the painting would continue and we can still receive mouse movement inputs and clicks for user interactions, but erratic mouse movements can not flood the message queue and stop the gdi+ painting of the user controls.

Any help specially, specially pointers to relevant apis or articles demonstrating techniques would be much appreciated. Thank you.

Upvotes: 0

Views: 103

Answers (1)

Gusman
Gusman

Reputation: 15161

It depends on the cause of the slow down when the draw is done.

First, you should optimize your drawing routines maybe you are painting the entire form/control on each call to OnPaint? If that's the case then you should only re draw the invalidated area, that will speed up things a lot.

Else, if you still need to do the drawing on another thread, then you cant do it directly, ui can only be modified on main thread, but you can use a bitmap as an off screen buffer and then re draw from it.

To do that, when your control is created you create also a bitmap of your controls size (also you should take care of resizes). So, when any change must be done to your control's appearance, draw it to the bitmap, you can do it in another thread, and then invalidate your control's updated area.

And finally, in your control's OnPaint just blit from that bitmap to your control, and only the invalidated area, this call will still be done on main thread, but i assure you any machine today is able of blitting very large images in milliseconds.

As an example, let's suppose you have a control where you draw a gradient background and a circle.

Usually, you will paint directly to the Control surface through a Graphics object each time you want to update something, let's say the background, so, to change it you will draw the full background and your circle over it.

To do that in background, if you created a bitmap as off screen buffer, you don't draw to the surface, you draw to the bitmap in another thread (obtaining a graphics object from it) and then invalidate the updated área of the control. When you invalidate the área OnPaint will be called and then you can blit from that bitmap to the controls surface.

In this step you gained little or none speed, but let's expand our example. Suppose you are drawing a very complex control,with lots of calls to DrawImage, DrawCircle, etc. When the mouse moves over the control, small áreas get invalidated, and on each OnPaint call you will draw all the "layers" composing the invalidated área, it can be lots of draws to do if as we said the control is very complex.

But if you did draw to a bitmap your controls appearance, on each OnPaint call you will just blit the corresponding área from the bitmap to the control, as you see you are reducing calls from lots of draws to just a blit.

Hope it clarifies the idea.

Upvotes: 2

Related Questions