none
backgroundWork组件,卡了两天了,麻烦版主帮我看看 RRS feed

  • 问题

  • Public Class FrmBackgroundWorker


    #Region " Shared data "

        Private mMin As Integer
        Private mMax As Integer
        Private mResults As New List(Of Integer)

    #End Region

    #Region " Primary thread methods "

        Private Sub btnStart_Click(ByVal sender As System.Object, _
          ByVal e As System.EventArgs) Handles BtnStart.Click

            ProgressBar1.Value = 0
            ListBox1.Items.Clear()
            mMin = 1
            mMax = 10000
            BackgroundWorker1.RunWorkerAsync()

        End Sub


        Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnCancel.Click

            BackgroundWorker1.CancelAsync()

        End Sub


        Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged

            ProgressBar1.Value = e.ProgressPercentage

        End Sub

        Private Sub BackgroundWorker1_RunWorkerCompleted( ByVal sender As Object, ByVal e As  _
          System.ComponentModel.RunWorkerCompletedEventArgs) _
          Handles BackgroundWorker1.RunWorkerCompleted

            For Each item As String In mResults
                ListBox1.Items.Add(item)
            Next

        End Sub

    #End Region

    #Region " Background thread methods "

        Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _
          ByVal e As System.ComponentModel.DoWorkEventArgs) _
          Handles BackgroundWorker1.DoWork

            mResults.Clear()

      'For count As Integer = mMin To mMax Step 2
            '    Dim isPrime As Boolean = True

            '    For x As Integer = 1 To CInt(count / 2)
            '        For y As Integer = 1 To x
            '            If x * y = count Then
            '                ' the number is not prime
            '                isPrime = False
            '                Exit For
            '            End If
            '        Next
            '        ' short-circuit the check
            '        If Not isPrime Then Exit For
            '    Next

            '    If isPrime Then
            '        mResults.Add(count)
            '    End If

            '    Me.BackgroundWorker1.ReportProgress( _
            '      CInt((count - mMin) / (mMax - mMin) * 100))

            '    If Me.BackgroundWorker1.CancellationPending Then
            '        Exit Sub
            '    End If

            'Next


            For i As Long = 1 To 100000
                mResults.Add(i)

                BackgroundWorker1.ReportProgress(CInt((i / 100000) * 100))    '异常有可能是这句话
                If BackgroundWorker1.CancellationPending Then
                    Exit For
                End If

            Next

        End Sub

    #End Region
    End Class

     

    我不知道异常出在哪里,但是在程序运行的时候发生界面锁死,恢复被注释的代码又不会锁死,麻烦高手帮我看看

    2011年1月24日 12:05

答案

  • 引用: 3.既要同时响应事件又要控件不变化,怎么办? 例如在一个长的循环中向listview控件中添加记录,无doevents时程序无响应,但有它时控件又闪的厉害 解决办法:a.不一定每次循环都doevents,可以在适当时间时才用,至少没那么闪 b.应用api函数 ValidateRect 功能是使指定的矩型区域生效,通知Windows不对指定的区域进行重画另:InvalidateRect 功能相反,同时需要用到函数 GetClientRect 取得指定对象的矩形区域应用*rect函数指定listview的矩形区不重画,即可避免闪烁(但还是要注意恢复重画,否则看不见了真实效果)
    grass...
    • 已标记为答案 Jarry_liu 2011年2月15日 1:17
    2011年2月5日 4:51

全部回复

  • 你好

    或者你可以嘗試使用

    THREADING 應該可以解決這個問題

    以解決這個問題

    可以參考以下URL

    http://blog.sharechiwai.com/2010/09/vb-net-threading-vb-net-%E7%B7%9A%E7%A8%8B/

     

    E.G.

     

     Private MyThreading As New System.Threading.Thread(AddressOf Me.LongProcess)

        Private Sub btnStart_Click(ByVal sender As System.Object, _

          ByVal e As System.EventArgs) Handles btnStart.Click

            CancelStatus = False

            ProgressBar1.Value = 0

            ListBox1.Items.Clear()

            mMin = 1

            mMax = 10000

            'BackgroundWorker1.RunWorkerAsync()

            Control.CheckForIllegalCrossThreadCalls = False

     

            '用.Start來 啟動這個線程Thread

            MyThreading.Start()

     

        End Sub

     

     Public Sub LongProcess()

     

            For i As Long = 1 To 100000

     

                mResults.Add(i)

     

                ProgressBar1.Value = (CInt((i / 100000) * 100))    '异常有可能是这句话

     

            Next

            ListBox1.DataSource = mResults

     

        End Sub

     

     Private Sub btnCancel_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click

            MyThreading.Abort() ' cancel threading

        End Sub

    Please correct me if my concept is wrong


    Chi
    2011年1月24日 14:01
    版主
  • 感谢您的回复,我想不明白为什么backgroundwork组件的问题出在哪里,我的设置backgroundwork.workReportProgress都设置为True了。

    我十分想找到原因,暂时不想走弯路。

    2011年1月24日 14:48
  • 我认为不是backgroundWork组件的问题,而是我代码的错误,但又不知道错在哪里。
    2011年1月24日 15:00
  • 你好

    或者你可以 改變一下以下的CODE

     

     Private Sub BackgroundWorker1_RunWorkerCompleted( ByVal sender As Object, ByVal e As  _
          System.ComponentModel.RunWorkerCompletedEventArgs) _
          Handles BackgroundWorker1.RunWorkerCompleted

     

     '       For Each item As String In mResults
      '          ListBox1.Items.Add(item)
       '     Next

    '把他變成

    ListBox1.DataSource = mResults

        End Sub

    可能會好一點

     

    和1

    ProgressBar1.Value = (CInt((i / 100000) * 100))    '异常有可能是这句话

    可不可以貼上這個ERROR MESSAGE

    給我們參考一下


    Chi
    2011年1月24日 15:07
    版主
  • 谢谢版主回复,实际上程序运行没有任何异常,只不过界面呈现锁死状态,不能移动。

    ProgressBar1.Value = (CInt((i / 100000) * 100))    '这句话没有报任何异常,只是我推测这句话可能写错了。


    注释掉我自己的代码,恢复原来计算素数的那段代码(也就是我注释的那段),程序运行没有任何问题。

    再次感谢您的热心回复。

    2011年1月24日 15:12
  • 对了,我的开发环境是vs2010,系统环境是windows7
    2011年1月24日 15:15
  • 你好

    這可能是原來的CODE 是

    mMax = 10000 

    和是用 STEP 2 ' 這應該是 +2 的 所是只有做 10000/2 = 5000 次

    而新的是

    For i As Long = 1 To 100000

    或者你可以改變一下原來的CODE 做一個對比

    E.G.

    'For count As Integer = mMin To mMax Step 2

    變成

    For count As Integer = mMin To 100000

    效果可能是差不多的

     

     


    Chi
    2011年1月24日 15:28
    版主
  • 不行,我测试过了,即使

    循环的周期值较小,也不能解决问题

    例如  for i as integer=1 to 5000  也会存在界面锁死情况。

    2011年1月24日 16:21
  • 慢是循环加list引起的 改成AddRange

    'Private mResults As New List(Of Integer) 
    Private mResults As New List(Of String) 
    
    
    'For Each item As String In mResults 
    ' ListBox1.Items.Add(item) 
    'Next 
    ListBox1.Items.AddRange(mResults.ToArray()) 
    
    
    'mResults.Add(i) 
    mResults.Add(i.ToString()) 

     

     


    http://feiyun0112.cnblogs.com/

    2011年1月25日 1:52
    版主
  • Feiyun0112感谢您的回复,可是我说的问题不是慢的原因,而是BackGroundWork组件没有作用,在程序运行的时候会发生界面锁死。

    麻烦再看看,谢谢。

    我试过你的建议,可是没有任何作用,在循环运行的过程中,依然会发生界面锁定。

    • 已编辑 Jarry_liu 2011年1月25日 2:38 继续回答
    2011年1月25日 2:37
  • 你好

    應該是這一句出現問題

     BackgroundWorker1.ReportProgress(CInt((i / 100000) * 100))   

    因而太過頻繁 UPDATE 你的GUI

    如果你COMMENT OUT 這一句便不會发生界面锁死

    所以應該要改一改這一句...只在 整數時才REPORT E.G. 1,2,3,4,5,6 

    不然會REPORT 100000 次

    Please correct me if my concept is wrong


    Chi
    2011年1月25日 9:18
    版主
  • 非常感谢,我想真正的原因在于用户界面更新过于频繁。但是怎么解决这个问题呢。

    如果用户界面更新确实需要这么频繁,应该如何解决?也就是说用户界面更新的频率是否有个临界值供参考?   

    comment out “BackgroundWorker1.ReportProgress(CInt((i / 100000) * 100))”这条语句 依然会发生界面锁死的情况。

    • 已编辑 Jarry_liu 2011年1月25日 11:52 补充
    2011年1月25日 11:49
  • 问题还没有解决,希望得到版主关注,谢谢。

    2011年1月26日 3:58
  • 这是我的代码,界面没锁死,而且很快就出来了数据
    Public Class Form1
    #Region " Shared data "
    
      Private mMin As Integer
      Private mMax As Integer
      Private mResults As New List(Of String)
    
    #End Region
    
    #Region " Primary thread methods "
    
      Private Sub btnStart_Click(ByVal sender As System.Object, _
       ByVal e As System.EventArgs) Handles BtnStart.Click
    
        ProgressBar1.Value = 0
        ListBox1.Items.Clear()
        mMin = 1
        mMax = 10000
        BackgroundWorker1.RunWorkerAsync()
    
      End Sub
    
    
      Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnCancel.Click
    
        BackgroundWorker1.CancelAsync()
    
      End Sub
    
    
      Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    
        ProgressBar1.Value = e.ProgressPercentage
    
      End Sub
    
      Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As _
       System.ComponentModel.RunWorkerCompletedEventArgs) _
       Handles BackgroundWorker1.RunWorkerCompleted
    
        'For Each item As String In mResults
        '  ListBox1.Items.Add(item)
        'Next
        ListBox1.Items.AddRange(mResults.ToArray())
    
      End Sub
    
    #End Region
    
    #Region " Background thread methods "
    
      Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, _
       ByVal e As System.ComponentModel.DoWorkEventArgs) _
       Handles BackgroundWorker1.DoWork
    
        mResults.Clear()
    
        'For count As Integer = mMin To mMax Step 2
        '  Dim isPrime As Boolean = True
    
        '  For x As Integer = 1 To CInt(count / 2)
        '    For y As Integer = 1 To x
        '      If x * y = count Then
        '        ' the number is not prime
        '        isPrime = False
        '        Exit For
        '      End If
        '    Next
        '    ' short-circuit the check
        '    If Not isPrime Then Exit For
        '  Next
    
        '  If isPrime Then
        '    mResults.Add(count)
        '  End If
    
        '  Me.BackgroundWorker1.ReportProgress( _
        '   CInt((count - mMin) / (mMax - mMin) * 100))
    
        '  If Me.BackgroundWorker1.CancellationPending Then
        '    Exit Sub
        '  End If
    
        'Next
    
    
        For i As Long = 1 To 100000
          mResults.Add(i.ToString())
    
          BackgroundWorker1.ReportProgress(CInt((i / 100000) * 100))  '异常有可能是这句话
          If BackgroundWorker1.CancellationPending Then
            Exit For
          End If
    
        Next
    
      End Sub
    
    #End Region
    
    
    End Class
    

    http://feiyun0112.cnblogs.com/
    2011年1月26日 6:36
    版主
  • 谢谢您的回复,我用了你的代码,还是会锁死界面。我的环境是windows7 .net4.0  vs2010

    2011年1月27日 12:41
  • 那就没办法,我是一样的环境

    试试不要循环,直接ListBox1.Items.AddRange(mResults.ToArray())

    看还锁不锁


    http://feiyun0112.cnblogs.com/
    2011年1月28日 1:06
    版主
  • 原理还是没弄明白,一直在瞎琢磨。会不会是因为64位系统的原因?
    2011年1月30日 13:05
  • 希望版主帮我再找找原因。。。。。。。。。。。。。
    2011年1月31日 14:06
  • 我觉得chiyu 解释得对, 你update UI 的频率太快了, 一口气10000各更新, 每个更新之间几乎是0秒。人的眼睛也没这么快的反应。


    这和在UI线呈上直接运行doWork 没什么两样了。 UI线呈是更新了,但还没绘制好,就又来了下一个的更新要求。

     

    你在 BackgroundWorker1.ReportProgress(CInt((i / 100000) * 100)) 前面加上Thread.sleep(500) 应该就没有锁死了。

    当然真正的解决,还是应该减少频繁更新。


       
    2011年1月31日 21:08
  • 谢谢,我按您说的再试试。
    2011年2月3日 16:29
  • 引用: 3.既要同时响应事件又要控件不变化,怎么办? 例如在一个长的循环中向listview控件中添加记录,无doevents时程序无响应,但有它时控件又闪的厉害 解决办法:a.不一定每次循环都doevents,可以在适当时间时才用,至少没那么闪 b.应用api函数 ValidateRect 功能是使指定的矩型区域生效,通知Windows不对指定的区域进行重画另:InvalidateRect 功能相反,同时需要用到函数 GetClientRect 取得指定对象的矩形区域应用*rect函数指定listview的矩形区不重画,即可避免闪烁(但还是要注意恢复重画,否则看不见了真实效果)
    grass...
    • 已标记为答案 Jarry_liu 2011年2月15日 1:17
    2011年2月5日 4:51