【问题标题】:Form doesn't update while running button click event运行按钮单击事件时表单不更新
【发布时间】:2013-11-27 13:51:42
【问题描述】:

我试图在 Visual Basic 中每个方法的末尾更新一个进度条,问题是 label1.Text 不会在每个方法的开始时自行更新,而是会更新。

Public Class Form2

    Private Const METHOD_COUNT = 4

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ProgressBar1.Maximum = METHOD_COUNT
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Method_One()
        Method_Two()
        Method_Three()
        Method_Four()
    End Sub

    Private Sub Method_One()
        Label1.Text = "Loading Method One"
        ProgressBar1.Value += 1
        'Threading.Thread.Sleep(1000)
    End Sub

    Private Sub Method_Two()
        Label1.Text = "Loading Method Two"
        ProgressBar1.Value += 1
        'Threading.Thread.Sleep(1000)
    End Sub

    Private Sub Method_Three()
        Label1.Text = "Loading Method Three"
        ProgressBar1.Value += 1
        'Threading.Thread.Sleep(1000)
    End Sub

    Private Sub Method_Four()
        Label1.Text = "Loading Method Four"
        ProgressBar1.Value += 1
        'Threading.Thread.Sleep(1000)
    End Sub
End Class 

所以基本上当你运行它时,它会很好地执行并更新进度条,但标签不会更新。我认为这可能与多线程有关,并且表单没有得到持续更新。

【问题讨论】:

    标签: vb.net multithreading forms progress-bar refresh


    【解决方案1】:

    “快速修复”是在每次调用Sleep()之前添加Application.DoEvents()

    Public Class Form2
    
        Private Const METHOD_COUNT = 4
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ProgressBar1.Maximum = METHOD_COUNT
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Method_One()
            Method_Two()
            Method_Three()
            Method_Four()
        End Sub
    
        Private Sub Method_One()
            Label1.Text = "Loading Method One"
            ProgressBar1.Value += 1
            Application.DoEvents()
            Threading.Thread.Sleep(1000)
        End Sub
    
        Private Sub Method_Two()
            Label1.Text = "Loading Method Two"
            ProgressBar1.Value += 1
            Application.DoEvents()
            Threading.Thread.Sleep(1000)
        End Sub
    
        Private Sub Method_Three()
            Label1.Text = "Loading Method Three"
            ProgressBar1.Value += 1
            Application.DoEvents()
            Threading.Thread.Sleep(1000)
        End Sub
    
        Private Sub Method_Four()
            Label1.Text = "Loading Method Four"
            ProgressBar1.Value += 1
            Application.DoEvents()
            Threading.Thread.Sleep(1000)
        End Sub
    
    End Class
    

    正确修复”是您的“工作”不应在主 UI 线程中完成,这就是您从按钮单击处理程序调用这些方法所做的事情。相反,您需要将工作移至后台线程,以便 UI 可以自行更新。看看使用 BackgroundWorker() 控件。您调用它的 ReportProgress() 方法来触发 ProgressChanged() 事件。从该事件中更新 UI 是安全的。当后台线程中的工作完成时,您将收到一个 RunWorkerCompleted() 事件。请注意,如果要使用进度事件,则必须将 WorkerReportsProgress() 属性设置为 True:

    Public Class Form2
    
        Private Const METHOD_COUNT = 4
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            ProgressBar1.Maximum = METHOD_COUNT
            BackgroundWorker1.WorkerReportsProgress = True
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If Not BackgroundWorker1.IsBusy Then
                Button1.Enabled = False
                BackgroundWorker1.RunWorkerAsync()
            End If
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Method_One()
            Method_Two()
            Method_Three()
            Method_Four()
        End Sub
    
        Private Sub Method_One()
            BackgroundWorker1.ReportProgress(1, "Loading Method One")
            Threading.Thread.Sleep(1000)
        End Sub
    
        Private Sub Method_Two()
            BackgroundWorker1.ReportProgress(2, "Loading Method Two")
            Threading.Thread.Sleep(1000)
        End Sub
    
        Private Sub Method_Three()
            BackgroundWorker1.ReportProgress(3, "Loading Method Three")
            Threading.Thread.Sleep(1000)
        End Sub
    
        Private Sub Method_Four()
            BackgroundWorker1.ReportProgress(4, "Loading Method Four")
            Threading.Thread.Sleep(1000)
        End Sub
    
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            Label1.Text = e.UserState
            ProgressBar1.Value = e.ProgressPercentage
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            Button1.Enabled = True
            MessageBox.Show("Done!")
        End Sub
    
    End Class
    

    【讨论】:

      【解决方案2】:

      如果您认为标签的值发生了变化,但屏幕没有更新,您是否尝试过刷新方法?

      例如:

          Private Sub Method_Three()
              Label1.Text = "Loading Method Three"
              Label1.Refresh
              ProgressBar1.Value += 1
              'Threading.Thread.Sleep(1000)
          End Sub
      

      【讨论】:

        【解决方案3】:

        我相信其他人可以解释为什么会这样,但我总是不得不使用以下方法来更新标签,否则它们不会更新:

        Private Sub Method_Three()
            With Label1
                .Text = "Loading Method Three"
                .Refresh
            End With
            ProgressBar1.Value += 1
            'Threading.Thread.Sleep(1000)
        End Sub
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-16
          • 2013-03-01
          • 1970-01-01
          • 2014-09-21
          • 1970-01-01
          • 1970-01-01
          • 2015-04-19
          • 1970-01-01
          相关资源
          最近更新 更多