How to block mouse click events from another form - c#

I have a winforms single form application that uses a "Thickbox" I've created whenever the loads a new view into the application form.
The "Thickbox" shows another form in front of the application's form that is semi-transparent and has a user control that is the box itself.
This thickbox can be shown a modal dialog and in that case I have no problems at all, but it can also be shown as a non modal, for instance, when the user switches views in the main form, it shows thickbox with a loading animated icon.
The problem is that when the thickbox is shown as non modal, it doesn't block the user from clicking on the buttons of main form of the application.
When thickbox is shown nothing happens, but as soon as it's closed, the click is being processed by the click event handler of the relevant button in the main form.
I can't use ShowDialog since I can't block the UI thread, and I need to get the indication from the main form when to close the thickbox,
I can't set the Enabled property of the owner form as described in this answer (though I've tried various versions of this solution, nothing helps)
I've tried using the win API function BlockInput as descried in this answer, but that didn't block the input,
I think my best chance is using the Application.FilterMessage method, but I couldn't get that to block the mouse clicks as well.
It would be great if I could encapsulate the mouse click blocking inside the thickbox form itself, so that it would be usable easily with other applications as well, but
a solution on to the calling form would also be very much appreciated.

I'm glad to announce that the problem is finally solved.
After spending a few days attempting to recreate this bug in a new application, re-constructing the main form in the application, comment out parts of the code in the main application, and generally just shooting all over to try and find a lead, It finally hit me.
The application behaved as if the clicks on the thickbox was queued somehow and only activated when the thickbox was closed. This morning, after fixing some other bugs, The penny finally dropped - all I was missing was a single line of code right before closing the thickbox's form:
Application.DoEvents();
The annoying thing is that it's not something that's new to me, I've used it many times before including in the main application and in the thickbox code itself... I guess I just had to let if go for a while to enable my mind to understand what was so painfully obvious in hindsight...

Related

How do I know that a MDI child form has visually changed?

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.

WPF - View getting minimized during navigation

I have a WPF application which behaves weird when another application is also opened. 'Another' application is developed using Panther. WPF apps behaves correctly with all other apps in the machine.
While both the applications opened, and when we click next on the WPF app, the app getting minimized even though its active as per windows active event.
WPF application is built using galasoft and follows slightly different approach in navigation compared to the pattern available when we search.
We initiate the Page from app.xaml.cs and based on the click, we invoke currentPage.Hide() and nextPage.Show() methods. All the navigations are written within App.xaml.cs file. Through a delegate the button click will be passed to app.xaml.cs file and the pages are switched.
Did anyone else face similar kind of issues?
Finally, I managed find an answer/work around to this issue.
In the existing design, the sequence of actions were Hide() the current view and Show() the next view.
Now, we modified the sequence to perform Show() the next screen first and then hide() the current screen. This way, the window was kept active and was visible to the user.

How to have a user navigate multiple "screens" within one form/window?

I am working on a project that simulates a company's program for performing various functions within a GUI (using C# on VS2010). Currently there are about 10 or so different forms, one for each function (serving as a menu, filling out assorted forms, management of said forms, ect). So far we've been using things along the line of:
Form1 myForm1 = new Form1();
myForm1.Show();
to open new screens and
this.Hide();
when finished with the currently active form. (this.Close() just seems to close the entire program)
This causes some issues in that the process has an issue of continuing to run after the X at the top right of the form is clicked (I think that this is due to hidden forms not being closed properly). I also suspect that if a user uses in-program navigation without killing the process long enough, the constant generation and hiding of forms will end up hogging up all the memory.
In the wild, I rarely see programs that rely on opening new windows/forms constantly to enable user navigation. Programs, such as an installer, typically use an event of some sort to cause the current displayed content to disappear and new content to appear without changing to a new form/window. How can I go about doing this? Is it a matter of having buttons/textboxes/labels all stacked on each other in the one screen, but hidden or is there something more intuitive that I am missing?
Have you looked in to using some kind of MDI setup: http://www.codeproject.com/Articles/7571/Creating-MDI-application-using-C-Walkthrough
The way you can do this (but isn't always feasible) is to make a UserControl for each screen. When its time to move on to the next screen, you simply hide the current user control and show the next one. So if you have 8 screens for example, you make each one into a user control.
Then on your MainForm's Load event, you initially hide all except the first one. When its time to move onto the second screen, you hide the first control and show the second, etc etc

How can I temporarily prevent a form from getting focus/activating?

my application opens n forms and the user can freely switch back and forth among these forms.
When the user decides to confirm the operations performed on one of the forms, I would like to block the other ones until this process (which can potentially open MessageBoxes and/or other forms) comes to an end.
It is not enough to disable the forms, since the user can't do anything on them, but the Activated event is fired, and this is exactly what I want to avoid.
I tried to set ControlStyles.Selectable to false to all these forms, but it doesn't work.
Just in order to make it clearer, the forms cover the whole screen, so the users activate them clicking on the taskbar. This is the situation where opening a modal form and having the confirm code executed there does not prevent the Activated event to be fired.
Try to use Form.ShowDialog() method.
You can use Form.ShowDialog Method method to display a modal dialog box in your application. When this method is called, the code following it is not executed until after the dialog box is closed.

How do I block all keyboard and mouse input to my WinForms app?

I have a WinForms app that is retrieving data from a web service on a worker thread and I need to disable all input to my app until the data is loaded.
Currently, I create a semi-transparent form and place it over my application. When the data call completes I close this overlay form. This works fine accept that it causes considerable performance problems for users running the application over terminal services. I tried making the overlay entirely transparent but that still triggers two redraws of the entire window so this did not help at all.
I know that a common recommendation for handling this is to disable all the controls, but that would also redraw much of the screen so I'm looking for another way to block all user input. Any assistance would be greatly appreciated!
UPDATE: I should have mentioned that we have considered the modal dialog. Currently we show the overlay, start the data access thread then construct the form. If there is no better way to block input (App.BlockInput() might be nice) then we could use the modal dialog idea, but we would need to wait until the form construction had completed and there isn't currently a nice, central location to do this.
You could display a small modal (modalForm.ShowDialog(yourForm)) form with progress bar rolling on top of your app. This won't cause big areas to be redrawed.
If your app really is blocked while the operation is running, I'd do what Microsoft frequently does: open a modal dialog box with some kind of throbber animation or ProgressBar, and a Cancel button. Redraw is limited because you're only drawing the size of the new dialog, and input to the rest of your application is blocked because the dialog is modal. Also, users are much more willing to wait when you have some kind of status updates and or animation, because it looks like the computer is "working".
However, if there are operations your user can do while your web service request is running, it's better to leave the controls accessible. At very least, there should always be a way to interrupt/abort the process.
Update: Since you now changed the question: How long is it taking to construct the modal dialog? Why not simply construct the dialog empty, and then populate its controls? If all you have is a small dialog box with a single button and a single ProgressBar, then calling dialog.ShowDialog() should happen faster than your user can interact with your UI. Is that not the case?
One thing you could try for keyboard input is setting the KeyPreview property of the form to True. This will pass all keyboard events to the Form object first instead of to the individual controls. Create an event handler for the KeyPress event of the form and in there you can set the Handled property of the KeyPressEventArgs to True to prevent the key stroke from being passed to any of the controls. If you're currently retrieving data from the web service, set the Handled property True otherwise set it to False and the key stroke will be passed to the controls.
If someone has a good idea on how to handle the mouse input yet you're set.
I'd typically create a LockUI() and UnlockUI() functions in my form that toggle controls and flip a local form field that acts a flag to indicate a long running process. This approach works really well if you use a command pattern.
As previously mentioned, you could toggle keyboard input by using the KeyPreview property of the form (as suggested by TLiebe).
As far as mouse input is concerned, you could disable mouse activity by hooking the WinProc messages and intercepting mouse input messages. This is basically what KeyPreview does.

Categories

Resources