How to clear keyboard buffer from stale messages - winforms

My WinForms application has a button. This button has accelerator key (e.g. Alt+L). When button is pressed I handle the Click event and disable UI to prevent further button clicks until processing is finished. However, when accelerator key is pressed using keyboard those keystrokes are queued and get processed as soon as UI is enabled again. I don't want this. My question is how to clear/flush keyboard buffer?
If I use KeyPress or KeyDown to eat those characters I don't know when they have been received. I only want to suppress old/stale messages that arrived when I was still processing first Click event.

Yes, indeed your theory of the problem is consistent with that proposed by both myself and madmik3 in the comment exchange above. The amount of work your application is doing on the UI thread is effectively blocking it from processing other events, including keystrokes by the user. Those are getting queued for later execution whenever your application finishes its time-consuming foreground task. Those are the perils of a modern-day, pre-emptive multitasking OS. Of course, without posting your actual code, the best I or anyone else can do is speculate about what the problem is, given our experience.
The quick check to confirm that this is actually the case is to toss Application.DoEvents into your processing loop. That will allow the OS to handle the keystrokes immediately, which will all fail because the button has been disabled. (Click events, whether initiated by the mouse or keyboard shortcuts, are not raised for a Button control that has its Enabled property set to "False".) This is the closest you'll get to anything like "flushing the buffers". I doubt you're receiving KeyDown or KeyPress events anyway until after whatever long-running task has completed.
If that fixes the problem, the long-term solution is to spawn a new thread and perform whatever processing you need to do there, instead of on your UI thread. This will prevent you from blocking your UI thread, and, assuming the Button control is correctly disabled, cause the keystrokes to get thrown away because the button they "click" is in a non-clickable state. The simplest way to create a new thread is using the BackgroundWorker component. The documentation contains a pretty good example.

Related

LabVIEW: how to stop a loop inside event structure

I create an event structure for two buttons, start ROI and stop ROI. When the user presses start ROI it goes to this event and do the following:
check if the camera is open and is in idle
enqueue "none" to the queue to initialize the queue
in the loop dequeue every iteration to find if there's invoked message, which is inserted from the callback
if the element is "invoked" then update the region
The problem I am seeing is that when it is in the loop I cannot press the stop ROI or any other buttons. But the ROI keeps updating. I am puzzled why this is happening.
Could you please help me ?
Thanks,
Edit events for that case (the one pictured in your screenshot) and make sure the box titled "Lock front panel" is unchecked. This should solve your issue.
As far as I can tell from the code you have shown, your event structure should not be attempting to handle the stop ROI Value Change event. It doesn't need to, because the only place you need to respond to that event is inside your innermost loop and there you are handling the button click by polling the value of its terminal anyway.
However as #Dave_St explains, this will only work if the loop runs regularly, i.e. if the Dequeue Element function either receives data regularly or has a short timeout, because otherwise it will wait for data indefinitely and the loop iteration will not complete until the dequeue has executed. Having an event handler for the button click can't help here because it can't interrupt the program flow - the event structure only waits for an event to happen and then allows the code in the corresponding frame to execute.
More generally though, and looking at your front panel which suggests you are going to want to deal with further controls and events, the problem is that you are trying to do a time-consuming task inside an event structure. That's not how event structures are designed to be used. You should use a design pattern for your app that separates the UI (responding to user input) from the process (acquiring images from a camera) - perhaps a queued message handler would be suitable. This may seem harder to understand at first but it will make your program much easier to develop, extend, and maintain.
You can find more information, examples and templates in your LabVIEW installation and its online help. I do recommend using one of the templates as your starting point if possible because they already implement a lot of common functionality and can save you a lot of redundant effort.

WPF's command firing twice on fast doubleclick

From a production application, we notice that our WPF buttons fire the ICommand.Execute method twice on fast double click.
Now, on every Command, the application is covered with a full-screen spinner animation, preventing any further interaction with the application.
This github repo contains a minimalistic repro of the issue. Note that:
when the Button's Command fires, the "IsBusy" flag is set to true
as a consequence, the BusyIndicator overlay will be shown
as a consequence, the Button cannot be pressed again until after 300ms
However, especially on slow computers, when fast double-clicking (really fast, like gaming fast that is), it is possible to fire the command twice without the BusyIndicator blocking the second call (this can be seen if the output shows 2 'click' lines right after one another).
This is unexpected behavior to me, as the IsBusy flag is set to true right away on the UI thread.
How come a second click is able to pass through?
I would expect the IsBusy Binding to show the overlay on the UI thread, blocking any further interaction?
The github sample also contains 2 workarounds:
using the ICommand.CanExecute to block the Execute handler
using the PreviewMouseDown to prevent double clicks
I'm trying to understand what the issue is.
What work-around would you prefer?
Diagnosis
This is only my guess and not a solid and confirmed info, but it seems that when you click the mouse button, the hit-testing is done immediately, but all the mouse related events are only scheduled to be raised (using the Dispatcher I presume). The important thing is that the control that is clicked is determined at the time the click occurred, and not after the previous click has been completely handled (including all UI changes that potentially follow).
So in your case, even if the first click results in showing the BusyIndicator covering (and thus blocking) the Button, if you manage to click for the second time before the BusyIndicator is actually shown (and that does not happen immediately), the click event on the Button will be scheduled to be raised (which will happen after the BusyIndicator is shown), causing the command to be executed again even though at that point the BusyIndicator will possibly be blocking the Button.
Solution
If your goal is to prevent command execution while the previous one is still executing the obvious choice is to make the Command.CanExecute result depend on the state of the IsBusy flag. Moreover, I wouldn't even call it a workaround, but a proper design.
What you're facing here is a clear-cut example of why you shouldn't make your business logic rely on UI. Firstly, because rendering strongly depends on the machine's processing power, and secondly because covering a button with another control by far does not guarantee the button cannot be "clicked" (using for example UI Automation framework).

Is there something like CDN_FILECANCEL analogous to CDN_FILEOK for getting when the user chooses Cancel in GetOpenFileName()?

For cross-platform parity reasons, my GetOpenFileName() specifies no owner and I explicitly disable all toplevel windows myself. The problem is re-enabling. In order to re-enable these windows correctly, I need to re-enable them before the dialog closes.
In the case of the user choosing a file, this is no issue: I just check for CDN_FILEOK in the hook procedure. No issues, no messed-up focus.
How can I do the same, but for cancelling the dialog box?
I have tried WM_DESTROY in the hook procedure, but that runs after the dialog box has been hidden (too late). I have tried WM_COMMAND, but that doesn't seem to cover all cases. I'm not sure what other options I have.
I need to target Windows XP and newer for now; that also means no Common Item Dialogs. Thanks!
Alternative: if there was a way to do a callback-based GetOpenFileName() that returned control to my message loop, like on Mac OS X with beginSheetModalForWindow:, I could be able to specify a parent window and avoid this hack.
There is no CDN notification when the dialog is canceled. If the user presses the Cancel button, you could try intercepting the BN_CLICKED notification that it sends to the dialog, or even subclass the button itself. But if the user cancels the dialog through other means (clicking the red X, pressing ESC, etc), you will likely have to catch the WM_CLOSE message instead.

WPF user interface with long processing execution hangs

I am extremely Sorry for this long post. I need some help on c# wpf issues. I have build a complicated UI(somehow) and there is some buttons... like start and stop and others.
When i click the start button a execution process starts with communicating with some protocol layer and others and it is a long process .. and during this process i have to show some notification UI like "Enter a Text", "Select Something" etc... this time i have to show some wpf window object... and after some time i have to automatically destroy the window and go with processing again.
At first i tried to run the execution in the Main window class. But it results that when the execution starts.. user can't click anything and ui doesno't respond rather just hangs. I investigate the problem... and found that UI is busy with processing in the execution on protocol layer so its not responding.
Here is my problem... can u give me some solution that...
i will have 2 button..start and stop
when i click the start button... a large process will start( like nested for loop with a large int which will continue for 50 seconds) in function named Processor.
at time of processing the function Processor will create several window and show them wait for 5-10 seconds and also destroy them. or user click;s on the window
And the whole time the stop button should be clickable so that when i click the stop button .. the process should be stop.
I tried this with backgroundworker, dispatcher... and using separate thread. but no luck. I guess i am missing something. because if i wait for some result showing a window..the window will definitely hang.. and if i separate them with different thread.. it will not communicate with each other. please give me some suggestions
Dispatcher is definitely the solution. You may need to set the Dispatcher Priority. Sharing some relevant code may also reveal some issues.
BackgroundWorker should do what you need. Set WorkerSupportsCancellation and WorkerReportsProgress to true.
I wouldn't suggest popping up multiple windows. Pop up one window to display status. In your loop in DoWork, call BackgroundWorker.ReportProgress. Then in the ProgressChanged event handler, update the status of the window.
To implement Stop:
In your DoWork method you need to check the CancellationPending property on the BackgroundWorker in your loop. When it is true you need to exit that method. On the stop button click, call BackgroundWorker.CancelAsync().

Why isn't my WPF closing event being fired for system closes?

I have the following line in my Window stanza in the XAML file:
Closing="Window_Closing"
I originally thought that the web page here assured me that this event fires when you use the big X close method, Alt-F4 or close from the system menu yet that doesn't appear to be the case since my breakpoint on the Window_Closing() function isn't being hit.
It does hit the breakpoint when I do the File, Exit method of exiting so that's working okay.
Re-reading that linked page leads me to believe that it may not trigger the closing event.
My questions are:
How do you catch the three methods listed in order to detect if your file is dirty and needs saving? I have all the 'dirty' and file saving code done, I just need to know how to trap the events.
Can you stop the exit from taking place with that method (as you can by intercepting the closing event)? In other words, if the user says they don't want to exit because the accidentally used Alt-F4 on the wrong window, can it be done?
According to the documentation page for the Closing event:
If a session ends because a user logs
off or shuts down, Closing is not
raised; handle SessionEnding to
implement code that cancels
application closure.
Therefore you'll want to make sure you handle the SessionEnding event as well as the Closing event. The SessionEnding event could be used to automatically save the current state to a temporary file that will be loaded again the next time the application starts. But if you do want to prompt the user, you can do so with a modal dialog box in SessionEnding but they will likely see the Windows screen that warns about unresponsive applications, giving them the chance to kill the process without responding to your dialog.
Try the Closed event instead: Closed="Window_Closing"

Resources