Search code examples
c#clickmousebufferwfp

Buffer button changing forms


this is my first post. I have a huge problem which make me headaches. I have an app uses WinForms, a TTS (Text-To-Speech) voice and custom-buttons with states.

In my 1st form -main- when I click a button, the app opens a 2nd form above the 1st. Ok. When I close the 2nd form trough a button, I tell the TTS say something and the form closed itself, viewing again the 1st form. Ok.

The problem starts when I click two times in the button on the 2nd form: the TTS says something, the button closes and the 'second click' is still in the click buffer (or somewhere) and it makes click in the 1st form (which appears 4 seconds later when I hit the button for the first time). I am using the voice in a Sync mode; if I use the voice in an Async mode, the application ends wit h a nice exception. If I click three or four times in the 2nd form, the other clicks still remains in buffer and clicks in the 1st form all the times.

I tried to (1) delete the DoubleClick event, (2) delete the event associated to the button and (3) hide the button which is clicked automatically when I return from the 2nd form, (4) hide the 1st form before create the 2nd and restore when it finishes.

Suggestions? Thanks!

PD: I'm sorry by my English :S

PD2: I've uploaded a very simple example of what happens.


Solution

  • EDIT 2

    Having looked at the code I understand the issue you're having now. The reason button clicks are being stacked up is when you call Speak within TTS the application locks up while it waits for the function to finish. Any presses in that time are stacked up until the application is free again to process them, you then close the form instanly before the messages are handled and these are then dealt with in the first form.

    I've come up with a few solutions which could work for you:

    1. Use only the SpeakAsync command within your TTS class and introduce a Waiting system where you wait for the speech to finish before doing anything. This will free the application and won't cause the mouse click events to stack up.

    2. After you trigger a Speak command you could access the Windows message list and clear all the mouse click events that occurred before the process finished. Unfortunately, I'm not sure how you'd implement this as I've not done this before. I think you need to overwrite the WndProc function but again I'm not sure. This might be also be a bit dangerous as you may end up clearing a perfectly valid or important system message by mistake. Sorry can't provide any more help on that one.

    3. Implement a background worker in your second form which will process the Speak commands seperately on a background thread. This again will free the application so the mouse click events won't stack up. I've modified your sample project and zipped it up for you to take a look. If you want I can explain further but essentially it does the following:

      • Form 2 loads and creates a background worker.
      • Worker_DoWork and Worker_WorkComplete delegates are created and set in the background worker. These functions are called when the worker is started and after the worker has finished.
      • Form 2 triggers the background worker to start. The background worker then sits in an infinite loop waiting for commands to process.
      • When the "Hello" button is pressed this sets a SayHello boolean to true, the worker spots this, carrys out the appropriate speak function and then resets the boolean ready for the next press.
      • When the "Close" button is pressed a CancelASync request is called in the background worker.
      • CancelASync interupts the BackgroundWorker's main loop (CancellationPending becomes true). The appropriate speak command is sent and the cancel property of the DoWorkEventArgs is set to true before breaking out of the BackgroundWorker's main loop.
      • Breaking out of the main loop causes Worker_WorkComplete to be called where the form is then closed.

    I hope you can follow the example (linked below) and I've explained it well enough here. I prefer this solution as its quite extendable, you can add more conditions within the main worker thread for example.

    Like I said, if you have any questions please ask and I'll try help as much as possible.

    Hope this helps.

    Example Link: http://www.mediafire.com/?2mf1yahto50ljs6