Reputation: 573
I am currently using some primitive animations in vb.net to improve the GUI for the end client. It's a thin panel strip that loops to extend underneath the textbox when it's entered.
It works pretty well. The problem I have is that the animation has to complete before the textbox will accept text. This means that when a user tabs between the "username" and "password" text boxes, they sometimes start typing too quickly for the animation to complete and therefore miss the first few characters of their password.
I have tried adding the "animation" code to a background worker, but this completely freezes the UI for around 20 seconds when tabbing between the two textboxes (it works fine when clicking, but tabbing causes the worker thread to freeze).
I have done some research and despite the suggestion, I'm not sure if a background worker would work in this instance, as ultimately, it'll just be updating the UI controls and that seems like it's against what the background worker is there to do.
This is how I had things setup:
Private Sub bwUsernameLines_DoWork(sender As Object, e As DoWorkEventArgs) Handles bwUsernameLines.DoWork
Dim x As Integer = 0
pnlUsername_under.Width = x
pnlUsername_under.Visible = True
'loop speed 1
Do Until x = 180
pnlUsername_under.Width = x
Threading.Thread.Sleep(5)
pnlUsername_under.Refresh()
x += 10
Loop
bwUsernameLines.CancelAsync()
End Sub
Private Sub txtUsername_Enter(sender As Object, e As EventArgs) Handles txtUsername.Enter
bwUsernameLines.RunWorkerAsync()
txtUsername.Text = vbNullString
End Sub
Tabbing into the textbox causes the UI to freeze whilst clicking into the textbox doesn't. Is there something I'm doing wrong to allow this to work, or is there a completely different way of doing this?
Essentially, all I want is for the loop animation to continue to play, whilst the textbox allows the entering of text still, rather than waiting for it to complete.
Upvotes: 0
Views: 748
Reputation: 216293
First thing to do is to change where you handle your panel resize. Has you have correctly understood, changing UI objects from a NON-UI thread is problematic and BackgroundWorker has been created to solve this problem in a WinForms application.
So we need to set something on the BackgroundWorker to prepare it for its task.
(You can do these changes through the Winform Designer or in code in your Form constructor but after the InitializeComponent)
' Define the event handler that runs the resize in the UI thread
AddHandler bwUsernameLines.ProgressChanged, AddressOf bwUsernameLines_SizeChanged
' Make sure that the backgroundworker reports the progress
bwUsernameLines.WorkerReportsProgress = True
Now your DoWork can be changed to just
Private Sub bwUsernameLines_DoWork(sender As Object, e As DoWorkEventArgs)
Dim x As Integer = 0
'loop speed 1
Do Until x = 500
Threading.Thread.Sleep(5)
' Raises the Progress_Changed event in the UI thread
' Notice that this overload takes an value that represent your progress so far
bwUsernameLines.ReportProgress(x)
x += 10
Loop
End Sub
Finally just add the event handler for the Progress_Changed event
Private Sub bwUsernameLines_SizeChanged(sender As Object, e As ProgressChangedEventArgs)
' Get that x passed above from the property ProgressPercentage
pnlUsername_under.Width = e.ProgressPercentage
End Sub
Upvotes: 1