首页 > 解决方案 > 如何在不锁定 UI 的情况下处理我的 Windows 窗体上的“动画”?

问题描述

我目前在 vb.net 中使用一些原始动画来改进最终客户端的 GUI。它是一个薄的面板条,在输入时会在文本框下方循环延伸。

它工作得很好。我遇到的问题是动画必须在文本框接受文本之前完成。这意味着当用户在“用户名”和“密码”文本框之间切换时,他们有时会因为输入太快而无法完成动画,因此会错过密码的前几个字符。

我尝试将“动画”代码添加到后台工作人员,但是当在两个文本框之间切换时,这会完全冻结 UI 大约 20 秒(单击时它工作正常,但切换会导致工作线程冻结)。

我已经做了一些研究,尽管有建议,但我不确定后台工作人员是否会在这种情况下工作,因为最终,它只会更新 UI 控件,这似乎与后台工作人员的存在背道而驰做。

这就是我设置东西的方式:

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

进入文本框会导致 UI 冻结,而单击文本框则不会。是否有什么我做错了让这个工作,或者有一个完全不同的方式来做到这一点?

本质上,我想要的只是循环动画继续播放,而文本框仍然允许输入文本,而不是等待它完成。

标签: vb.netmultithreadingvisual-studio

解决方案


首先要做的是更改处理面板调整大小的位置。您是否正确理解,从 NON-UI 线程更改 UI 对象是有问题的,并且创建了 BackgroundWorker 来解决 WinForms 应用程序中的这个问题。

所以我们需要在 BackgroundWorker 上设置一些东西来为它的任务做准备。
(您可以通过 Winform 设计器或在 Form 构造函数中的代码中进行这些更改,但在 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

现在您的 DoWork 可以更改为

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

最后只需为 Progress_Changed 事件添加事件处理程序

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 

推荐阅读