I have a form with several buttons on it. When a button is pressed, it will execute some remoting proxy method on the server. There is some delay in the process before there is a result returned from server.
Currently, I tried to disable the button in the _Click event, hoping that a 2nd, 3rd and the following clicks would not be registered. Unfortunately, those input from the mouse clicks were queued by Windows.
So once the _Click event has finished running, it will immediately get executed again due to the earlier clicking.
I tried to create a form (Notice) to display some status message, hoping that clicks won't be registered on the button. Despite setting the form to maximize and on top of the caller form, the clicks still get registered.
Then I thought of using .ShowDialog(). Unfortunately, it halts the processing until I close the form. So I did something more complicated by passing in the method into Notice form, so that it would execute the _Click method via an address pointer.
Unfortunately, after all these coding. The buttons still get registered with the mouse clicks.
So now, is there any way to overcome this clicking queue that Windows registered?
When you run it, click on Button1 for 3 times, then Button2 for 1 time.
Wait for it to run. You can move your mouse away or whatnot. You'll notice that the Button1 will be executed 3 times by looking at the counter on Button3.Text.
Thank you.
vb Code:
Public Class Form1
Dim intCount As Integer = 1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Button3.Text = intCount.ToString()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim btnTmp As Button = CType(sender, Button)
btnTmp.Enabled = False
'sleep for 1 second
System.Threading.Thread.Sleep(1000)
'update button 3
intCount += 1
Button3.Text = intCount.ToString
'sleep again for 1 second
System.Threading.Thread.Sleep(1000)
btnTmp.Enabled = True
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
MessageBox.Show("No tricks here")
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
MessageBox.Show("I just want to go home!")
Me.Close()
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim btnTmp As Button = CType(sender, Button)
intCount += 1
btnTmp.Text = intCount.ToString
End Sub
End Class
Last edited by Harddisk; Mar 22nd, 2011 at 07:45 AM.
Well, if you're still looking I think you just have to reference the buttons directly in code:
Code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Button1.Enabled = False
System.Threading.Thread.Sleep(1000)
Button1.Enabled = True
End Sub
I tested this and as soon as I clicked Button1 it became disabled for 1 second
Last edited by GDeRousse; Mar 24th, 2011 at 01:29 PM.
Well, if you're still looking I think you just have to reference the buttons directly in code:
Code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Button1.Enabled = False
System.Threading.Thread.Sleep(1000)
Button1.Enabled = True
End Sub
I tested this and as soon as I clicked Button1 it became disabled for 1 second
Well, if you're still looking I think you just have to reference the buttons directly in code:
Code:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Button1.Enabled = False
System.Threading.Thread.Sleep(1000)
Button1.Enabled = True
End Sub
I tested this and as soon as I clicked Button1 it became disabled for 1 second
If you read my earlier description, I wasn't having problem about disabling button, but rather disabling mouse click/input.
Try to do multiple click at 1 shot, for eg, 3 - 5 times. Then move your mouse away. Even when the button was disabled, it still registers the follow clicks.
Does that mean, if I run it in "Release" mode, it might not occur? Though I haven't tested that (call via function pounter) using Release code, but the disable button definitely won't work the way I want.
Pradeep, Microsoft MVP (Visual Basic) Please appreciate posts that have helped you by clicking icon on the left of the post.
"A problem well stated is a problem half solved." — Charles F. Kettering
That was in fact what I was about to try next. Unfortunately, there were many extra coding required just for a simple task to be achieved here.
I was still searching for a PropertyInvoker or something similar which could perform thread-safe operation on setting Property values dynamically, rather than creating extra Subs to handle the settings of property.
The simple example here works very well, but for my actual method to work out in order for the cross-thread to work, it's too much of a trouble.
Try declaring "counter" as public variable under MyApplication Class. Then do the update accordingly as per DoProcess sub. Problem is, how do I cross-thread to MyApplication's thread to update the variable?
You don't have to "cross-thread" anything to update a variable. You need to invoke a method on the UI thread to access the UI. That's all. Doing so is not difficult. You simply write your method as you normally would, then identify each section that accesses the UI and refactor that into its own method. You then use the ISynchronizeInvoke interface or the SynchronizationContext class to invoke that method on the UI thread. The main reason people have issues with this is because they don't understand WHY they're doing it. If you understand the WHY then the WHAT is completely logical.
Somehow now my pop up form (ShowDialog() after executing the threading object) is not showing most of the time. With the ShowDialog(), I could somehow block the subsequent mouse clicks to the button, along with setting button disable.
Last edited by Harddisk; Mar 25th, 2011 at 04:22 AM.
Let's say that you have a Button. In the Click event handler, you disable the Button, do some work and then re-enable the Button. Now, let's say that you click the Button and then, while the work is being done, you click it again. On the second click, because the UI thread is busy doing something else, the click doesn't get processed. Only once the work is done is the UI thread freed up to process the second click. By then, the Button has been re-enabled so the Click event does get raised.
Now, this could be construed as a bug but it's really an example of why you aren't supposed to perform long-running tasks on the UI thread.
Let's say that you have a Button. In the Click event handler, you disable the Button, do some work and then re-enable the Button. Now, let's say that you click the Button and then, while the work is being done, you click it again. On the second click, because the UI thread is busy doing something else, the click doesn't get processed. Only once the work is done is the UI thread freed up to process the second click. By then, the Button has been re-enabled so the Click event does get raised.
Now, this could be construed as a bug but it's really an example of why you aren't supposed to perform long-running tasks on the UI thread.
I'm not sure if it's a bug or just how Windows queued the inputs from the I/O.
As for the long running task. Well, the button click will invoke remote methods to retrieve some data, then print something via the printer. No matter how fast it goes, it still takes 500ms - 1000ms at least and sometimes takes about 2 seconds. Maybe my existing machine which run the program was a Pentium4, hence the delay. But I do want to make sure that during the delay of data retrieval and printing, any user interactions would not be registered, or they are blocked. Cause I get complains from users that, multiple printings were generated due to the delay and user clicked on it multiple times.
EDIT: Attached the most current test button code. Both Invokes gave different behaviour. Button1 has better response and closer to what I want. Button2 is easier to code by wrapping the Invoke code in the IF's statement, but the dialog doesn't close properly.
Last edited by Harddisk; Mar 25th, 2011 at 05:54 AM.
Read jm's posts again.. I think he has explained it very clear and complete. I don't have anything to add to it.
Pradeep, Microsoft MVP (Visual Basic) Please appreciate posts that have helped you by clicking icon on the left of the post.
"A problem well stated is a problem half solved." — Charles F. Kettering