线程和后台工作者

时间:2013-11-11 19:57:47

标签: vb.net multithreading background worker

我正在尝试制作一些可以检查Xbox用户名的内容,但我尝试使用一个落后于它的UI的计时器。所以我想我是用后台工作者做的,但是使用不同的线程,并且调用UI引用并不适合我。有什么帮助吗?

        For i As Integer = 0 To ListBox1.Items.Count
        Using Wc As New WebClient()
            Try
                Dim Xbox As String = String.Empty
                Xbox = Wc.DownloadString("http://www.xboxgamertag.com/search/" & ListBox1.SelectedItem.ToString())

                If Xbox.Contains("Online Status") Then
                    FlatAlertBox1.Text = "Gamertag " & ListBox1.SelectedItem.ToString & " is taken :("
                    FlatAlertBox1.kind = FlatAlertBox._Kind.Error
                    FlatAlertBox1.Visible = True
                End If

            Catch ex As Exception
                FlatAlertBox1.Text = "Gamertag " & ListBox1.SelectedItem.ToString & " is not taken!"
                FlatAlertBox1.kind = FlatAlertBox._Kind.Success
                FlatAlertBox1.Visible = True
            End Try

        End Using
    Next
    ListBox1.SelectedIndex += 1

当我尝试运行它时,我得到:

  

System.Windows.Forms.dll中发生了'System.InvalidOperationException'类型的异常,但未在用户代码中处理

     

附加信息:跨线程操作无效:控制从其创建的线程以外的线程访问的“ListBox1”。

     

如果存在此异常的处理程序,则可以安全地继续该程序。

在线:FlatAlertBox1.Text = "Gamertag " & ListBox1.SelectedItem.ToString & " is not taken!"

1 个答案:

答案 0 :(得分:0)

您无法在非UI线程上更新GUI控件,因此您必须在循环期间尝试“报告”调查结果。

这里我只使用ListBox中的字符串副本启动线程:

bgw.RunWorkerAsync(ListBox1.Items.Cast(Of String))

我们需要一个简单的类来报告信息:

Public Class UserStatus
  Property Name As String
  Property Kind As Integer
End Class

然后在DoWork方法中

Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
  For Each s As String In DirectCast(e.Argument, IEnumerable(Of String))
    Using Wc As New WebClient()
      Dim Xbox As String = String.Empty
      Xbox = Wc.DownloadString("http://www.xboxgamertag.com/search/" & s)
      If Xbox.Contains("Online Status") Then
        bgw.ReportProgress(0, New UserStatus() With {.Name = s, .Kind = Kind.Error})
      Else
        bgw.ReportProgress(0, New UserStatus() With {.Name = s, .Kind = Kind.Success})
      End If
    End Using
  Next
End Sub

在ProgressChanged事件中,您已阅读状态:

Private Sub bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
  Dim us As UserStatus = DirectCast(e.UserState, UserStatus)
  If us.Kind = Kind.Success Then
    FlatAlertBox1.Text = "Gamertag " & us.Name & " is not taken!"
  Else
    FlatAlertBox1.Text = "Gamertag " & us.Name & " is taken :("
  End If
  FlatAlertBox1.kind = us.Kind
  FlatAlertBox1.Visible = True
End Sub

关于你的代码的一些注意事项。您循环遍历列表但将所有信息放在同一个TextBox中,因此您只能看到列表中的最后一项(除非过程非常慢)。

我删除了Try-Catch。如果BackgroundWorker中发生错误,则会在e.Error属性中的RunWorkerCompleted事件中报告该错误。您应该检查那里发生的任何错误。