I have a vb.net based windows application, where when "GO" button is clicked a bunch of data is loaded into DB. So in my application as soon as "GO" button is clicked I want to just disable it and would like to enable it back when the uploading has completed. Now in my specific method for btnGo_Click() I have:
btnGo.Enabled = False
as first line and
btnGo.Enabled = True
as last line in the same method.
But I fail to understand why the "GO" though appears as being disabled still allows click when processing is going on. Also if I remove the last line, it gets disabled permanently and doesn't allow the click event.
Kindly suggest what am I doing wrong?
Edit (Dated: 25th Jan 2012): I made changes as suggested by our collegues, but I am facing a new issue here. I am facing an issue where the textbox gets updated but not always. I have updated my textbox in "_ProgressChanged" event of the background worker thread. In my case if there is 10 records uploaded. Then there are 10 lines of updates that are expected in the texbox. But only few lines are shown in the textbox. Is it the repaint issue again? Kindly suggest...Because all other things are done as per your suggestion
It's usually not a good idea to manage the state of a submit button. Instead, perform validation on submit.
Since you're trying to execute a function that can take some time, I'd advise you to make use of threading. In .NET there's a BackgroundWorker component which is excellent for performing tasks asynchronous.
On button click, invoke the BackgroundWorker like this:
And use the completed event to enable the button again:
In the example above, I've used bgwWorker as the instance of a BackgroundWorker.
You're not doing anything wrong. The problem is that the UI doesn't get updated until the code inside of your event handler method finishes executing. Then, the button is disabled and immediately enabled in rapid sequence.
That explains why if you forget to reenable the button control at the end of the event handler method, it is still disabled—because you told it to disable the button in the first line of the method.
This is a classic case of why you should never perform long-running computational tasks inside of an event handler method, because it blocks the UI from being updated. The computation actually needs to happen on a separate thread. But don't try to create the thread manually, and definitely don't try to update your UI from a separate thread. Instead, use the
BackgroundWorker
component to handle all of this for you automatically. The linked MSDN documentation has a great sample on how to use it.Disable the button before starting the
BackgroundWorker
, and then re-enable it in itsCompleted
event, signaling the completion of your database load.If your
btnGo_Click()
is ran inside main thread, UI could not be updated correctly inside a time-consuming task.The best way you can do what you need is running your method in a BackgroundWorker.
I just tried disabling a button,
Update
ing the form,Sleep
ing, and enabling it again. It still performed the click (A click that was done while it "slept" with the button disabled) after it was enabled.I guess forms "remember" clicks.
(EDIT: I did this in C#.)
The button click event is handled as soon as the UI thread has idle time. After you disable your button, the UI thread is keept busy by your code. At the end of your method, you re-enable the button, and after that you exit the method and allow for idle time. As a consequence, the button will already be enabled at the point in time where the click event is handled, so your click is "recognized".
The solution is, as others already suggested, to use a Backgroundworker.
Dont try to use doEvents() as a solution (never do), since this would be prone to introduce other subtle problems. That said, you can prove the above explanation with some experimental doEvents in your code. You will see that the click is discarded if a doEvents is performed before the button gets re-enabled. On the other hand, performing a doEvents directly after the button.disable (to "update the GUI") will not help if it is executed before the click.