1

I have MDI WinForms application written in C#. Normally only one MDI child form is visible and all others are in background. Child forms content may occasionally change in background (for example, web browser control may be displaying a page that is dynamically changing every N seconds, chart controls are being filled with data as time goes on).

I want to show small previews of child forms when user hovers a mouse over or clicks on a special button in a toolbar of the main form. I can successfully use PrintWindow function as described here to make screenshots of child MDI forms. This works even for non-active child forms. The only problem is that taking every screenshot may take significant time (about 100-120 ms), probably because of the complex structure of the forms, so that if I make screenshots right before I want to show the previews then this creates a noticeable delay, especially when there are a lot of child forms (e.g. 10-15).

I want to optimize this and re-create screenshots only when it is really needed. Here is what I mean. Initially would I create screenshots for all the forms, store them in a "cache" and show previews. Later, when I need to create previews again, I would like to determine somehow that visual content of MDI form has changed (or change is pending) and re-create the screenshot only in that case, and otherwise use "cached" screenshot.

I tried to implement this by overriding of WndProc function of the child form class and looking for some messages like WM_PAINT or WM_SETREDRAW. But when I log all messages I see neither WM_PAINT nor WM_SETREDRAW even while the form is active (in foreground) and the web browser control on it constantly updates its page. Probably those event are sent directly to the controls of the form, but not to the form itself.

I don't want to traverse every form and connect to "changed" events of all the controls, because all of them are very different and not all have such notification events.

I guess that every control when it wants to change its visual representation sends some notification to OS to force self repaint. So, is there any way to detect such notification from any control inside MDI child form?

UPDATE: I found WinAPI GetUpdateRect function that should return a rectangle that needs to be redrawn. I thought that if it returned non-empty rectangle then that would mean the screenshot needs to be updated. I tried to call it before the call to PrintWindow, but it always returns empty rectangle.

Roman
  • 515
  • 5
  • 16
  • Well, that *something* that changes the Forms' contents in the background, should know when this is happening, right? You could raise an event, subscribe it in a *Manager* class, which should process the whole thing in a different thread, so the MDI Parent won't stutter while the Bitmaps are created (btw, 100-200 ms looks like a lot of time to create a thumbnail). – Jimi Mar 31 '19 at 20:49
  • Yes, but generally that means I would have to subscribe to such notifications from every component inside every form and not forget to do that if I add some new form. Doable, but not really elegant. – Roman Apr 01 '19 at 07:35
  • That's why I suggeted a Manager class. Since you want to recreate the thumbnail of a whole Form, you don't need each control affected to notify the change. You just need to know that *something* has changed. Whatever that is, you need to redraw the thumbnail. Since you didn't specify what causes changes in the UI, nothing specific can be said. Point is, a procedure caused this. This procedure should provide the notification. – Jimi Apr 01 '19 at 07:45
  • By "Manager" class do you mean something self-written, or some standard class in dotNet framework? – Roman Apr 01 '19 at 07:50
  • It depends on what you're doing, in practice. Are these controls bound to a data source? You could use the notifications provided by the BindingSource. Or have a class that implements `INotifyPropertyChange`. Or simply a class that *knows* that something is about to happen, that this *something* will affect the UI and take action accordingly. This class should not interfere/interact with the UI (is separated from the Forms and the main thread) and perform its processes in a different thread. Thread as a loose term. You have CPU-bound work, so probably Tasks. – Jimi Apr 01 '19 at 08:02

0 Answers0